定時器timerfd

1.為什么要加入此定時器接口

linux2.6.25版本新增了timerfd這個供用戶程序使用的定時接口,這個接口基于文件描述符,當超時事件發生時,該文件描述符就變為可讀。我首次接觸這個新特性是在muduo網絡庫的定時器里看到的,那么新增一個這樣的定時器接口有什么意義呢?

要說明這個問題我得先給大家列舉一下Linux下能實現定時功能的各個接口,然后通過逐一比較來說明原因

linux下的定時接口主要有如下幾種

  1. .sleep()

  2. .alarm()

  3. .usleep()

  4. .nanosleep()

  5. .clock_nanosleep()

  6. .getitimer()/setitimer()

  7. .timer_create()/timer_settime/timer_gettime()/timer_delete()

  8. .timerfd_create()/timerfd_gettime()/timer_settime()

以上便是Linux下常用的一些定時接口?
1.前三種sleep()/alarm()/usleep()在實現時可能用了SIGALRM信號,在多線程中使用信號是相當麻煩的?
2.nanosleep()/clock_nanosleep()會讓線程掛起,這樣會使程序失去響應,多線程網絡編程中我們應該避免這樣做?
3.getitimer()/timer_cteate()也是用信號來deliver超時

而我們的timerfd_create()把時間變成了一個文件描述符,該文件描述符會在超時時變得可讀,這種特性可以使我們在寫服務器程序時,很方便的便把定時事件變成和其他I/O事件一樣的處理方式,并且此定時接口的精度也足夠的高,所以我們只要以后在寫I/O框架時用到了定時器就該首選timerfd_create()

2.timerfd的接口介紹

(1)timerfd的創建

 
  1. int timer_create(int clockid,int flags);

  2. ?
  3. //成功返回0

?

第一個參數一般為CLOCK_REALTIME或者CLOCK_MONOTONIC,其參數意義為參數意義

CLOCK_REALTIME:相對時間,從1970.1.1到目前時間,之所以說其為相對時間,是因為我們只要改變當前系統的時間,從1970.1.1到當前時間就會發生變化,所以說其為相對時間

CLOCK_MONOTONIC:與CLOCK_REALTIME相反,它是以絕對時間為準,獲取的時間為系統最近一次重啟到現在的時間,更該系統時間對其沒影響

第二個參數為控制標志:TFD_NONBLOCK(非阻塞),TFD_CLOEXEC(同O_CLOEXEC)

(2)定時器的設置

 
  1. int timerfd_settime(int fd,int flags

  2. const struct itimerspec *new_value

  3. struct itimerspec *old_value);

  4. //成功返回0

?

該函數的功能為啟動和停止定時器,第一個參數fd為上面的timerfd_create()函數返回的定時器文件描述符,第二個參數flags為0表示相對定時器,為TFD_TIMER_ABSTIME表示絕對定時器,第三個參數new_value用來設置超時時間,為0表示停止定時器,第四個參數為原來的超時時間,一般設為NULL

需要注意的是我們可以通過clock_gettime獲取當前時間,如果是絕對定時器,那么我們得獲取1970.1.1到當前時間(CLOCK_REALTIME),在加上我們自己定的定時時間。若是相對定時,則要獲取我們系統本次開機到目前的時間加我們要定的時常(即獲取CLOCK_MONOTONIC時間)

上述參數中itimerspec的結構定義如下

 
  1. struct itimerspec {

  2. struct timespec it_interval; /* Interval for periodic timer */

  3. struct timespec it_value; /* Initial expiration */

  4. };

?

其中it_value保存首次超時時間值,即在哪個時間點超時的那個時間的值,it_interval為后續周期性超時的時間間隔,注意是時間間隔不是時間值啦?
timespec的結構定義如下

 
  1. struct timespec {

  2. time_t tv_sec; /* Seconds */

  3. long tv_nsec; /* Nanoseconds */

  4. };

?

需要注意的是當設置定時器后,我們就可以用read讀取定時器的文件描述符了,當其可讀時,就是超時發生的時間,下面的實例中給出用法,請讀者仔細體會

3.具體實例

以絕對超時為例

 
  1. #include <sys/timerfd.h>

  2. #include <time.h>

  3. #include <unistd.h>

  4. #include <stdlib.h>

  5. #include <stdio.h>

  6. #include <stdint.h> /* Definition of uint64_t */

  7. ?
  8. #define handle_error(msg) \

  9. do { perror(msg); exit(EXIT_FAILURE); } while (0)

  10. ?
  11. ?
  12. //打印當前定時距首次開始計時的時間

  13. static void print_elapsed_time(void)

  14. {

  15. static struct timespec start;

  16. struct timespec curr;

  17. static int first_call = 1;

  18. int secs, nsecs;

  19. ?
  20. if (first_call) { //獲取開始時間

  21. first_call = 0;

  22. if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)

  23. handle_error("clock_gettime");

  24. }

  25. ?
  26. if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)

  27. handle_error("clock_gettime");

  28. ?
  29. //時間差等于每次的當前時間減去start的開始時間

  30. secs = curr.tv_sec - start.tv_sec;

  31. nsecs = curr.tv_nsec - start.tv_nsec;

  32. if (nsecs < 0) {

  33. secs--;

  34. nsecs += 1000000000; //相差的納秒數

  35. }

  36. printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000);

  37. }

  38. ?
  39. ?
  40. int main(int argc, char *argv[])

  41. {

  42. struct itimerspec new_value;

  43. int max_exp, fd;

  44. struct timespec now;

  45. uint64_t exp, tot_exp;

  46. ssize_t s;

  47. ?
  48. if ((argc != 2) && (argc != 4)) {

  49. fprintf(stderr, "%s init-secs [interval-secs max-exp]\n",

  50. argv[0]);

  51. exit(EXIT_FAILURE);

  52. }

  53. ?
  54. if (clock_gettime(CLOCK_REALTIME, &now) == -1)

  55. handle_error("clock_gettime");

  56. ?
  57. /* Create a CLOCK_REALTIME absolute timer with initial

  58. expiration and interval as specified in command line */

  59. ?
  60. new_value.it_value.tv_sec = now.tv_sec + atoi(argv[1]);

  61. new_value.it_value.tv_nsec = now.tv_nsec;

  62. if (argc == 2) {

  63. new_value.it_interval.tv_sec = 0;

  64. max_exp = 1;

  65. } else {

  66. new_value.it_interval.tv_sec = atoi(argv[2]); //之后的定時間隔

  67. max_exp = atoi(argv[3]); //定時總次數

  68. }

  69. new_value.it_interval.tv_nsec = 0;

  70. ?
  71. //生成與定時器關聯的文件描述符

  72. fd = timerfd_create(CLOCK_REALTIME, 0);

  73. if (fd == -1)

  74. handle_error("timerfd_create");

  75. if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1)

  76. handle_error("timerfd_settime");

  77. ?
  78. //獲取并打印首次首次定時開始的時間

  79. print_elapsed_time();

  80. printf("timer started\n");

  81. ?
  82. for (tot_exp = 0; tot_exp < max_exp;) {

  83. s = read(fd, &exp, sizeof(uint64_t)); //read阻塞等待知道超時發生

  84. if (s != sizeof(uint64_t))

  85. handle_error("read");

  86. ?
  87. tot_exp += exp;

  88. print_elapsed_time();

  89. printf("read: %llu; total=%llu\n",

  90. (unsigned long long) exp,

  91. (unsigned long long) tot_exp);

  92. }

  93. ?
  94. exit(EXIT_SUCCESS);

  95. }

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384980.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384980.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384980.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

文件操作(讀)

讀一行&#xff1a; #include<stdio.h> #include<string.h> #include<stdlib.h> const int maxn 10; int main() {char s[1024] {0};FILE *p fopen("/home/exbot/wangqinghe/C/20190716/file.txt","r");//第一個參數是一個內存地址&…

timerfd與epoll

linux timerfd系列函數總結 網上關于timerfd的文章很多&#xff0c;在這兒歸納總結一下方便以后使用&#xff0c;順便貼出一個timerfd配合epoll使用的簡單例子 一、timerfd系列函數 timerfd是Linux為用戶程序提供的一個定時器接口。這個接口基于文件描述符&#xff0c;通過文…

文件操作(解密加密)

文件加密&#xff1a; #include<stdio.h> #include<string.h> #include<stdlib.h>void code(char *s) {while(*s){(*s);s;} }int main() {char s[1024] {0};FILE *p fopen("/home/exbot/wangqinghe/C/20190716/file.txt","r");FILE *p…

linux僵尸進程產生的原因以及如何避免產生僵尸進程defunct

給進程設置僵尸狀態的目的是維護子進程的信息&#xff0c;以便父進程在以后某個時間獲取。這些信息包括子進程的進程ID、終止狀態以及資源利用信息(CPU時間&#xff0c;內存使用量等等)。如果一個進程終止&#xff0c;而該進程有子進程處于僵尸狀態&#xff0c;那么它的所有僵尸…

linux下僵尸進程(Defunct進程)的產生與避免

在測試基于 DirectFBGstreamer 的視頻聯播系統的一個 Demo 的時候&#xff0c;其中大量使用 system 調用的語句&#xff0c;例如在 menu 代碼中的 system("./play") &#xff0c;而且多次執行&#xff0c;這種情況下&#xff0c;在 ps -ef 列表中出現了大量的 defunc…

文件操作函數

fopen()函數參數&#xff1a; r 只讀的方式打開文件。 打開成功返回文件指針&#xff0c; 打開失敗返回NULL r 以讀寫方式打開文件。 文件必須存在 rb 以二進制模式讀寫文件&#xff0c;文件必須存在 rw 讀寫一個二進制文件&#xff0c;允許讀和寫 w 打開只寫文件&…

讀過的最好的epoll講解

首先我們來定義流的概念&#xff0c;一個流可以是文件&#xff0c;socket&#xff0c;pipe等等可以進行I/O操作的內核對象。 不管是文件&#xff0c;還是套接字&#xff0c;還是管道&#xff0c;我們都可以把他們看作流。 之后我們來討論I/O的操作&#xff0c;通過read&#xf…

文件操作函數(讀寫)

文件文本排序&#xff1a; 數組冒泡&#xff1a; #include<stdio.h>void swap(int *a,int *b) {int temp *a;*a *b;*b temp; }void bubble(int *p,int n) {int i;int j;for(i 0; i < n; i){for(j 1; j < n - i; j){if(p[j - 1] > p[j]){swap(&p[j-1],&…

文件操作(升級)

計算字符串“25 32 ” #include<stdio.h> #include<string.h>int calc_string(char *s) {char buf1[100] {0};char oper 0;char buf2[100] {0};int len strlen(s);int i;for(i 0; i < len; i){if( s[i] || - s[i] || * s[i] || / s[i] ){strncpy…

C語言指針轉換為intptr_t類型

C語言指針轉換為intptr_t類型 1、前言 今天在看代碼時&#xff0c;發現將之一個指針賦值給一個intptr_t類型的變量。由于之前沒有見過intptr_t這樣數據類型&#xff0c;憑感覺認為intptr_t是int類型的指針。感覺很奇怪&#xff0c;為何要將一個指針這樣做呢&#xff1f;如是果…

nginx epoll詳解

nginx epoll 事件模型 nginx做為一個異步高效的事件驅動型web服務器&#xff0c;在linux平臺中當系統支持epoll時nginx默認采用epoll來高效的處理事件。nginx中使用ngx_event_t結構來表示一個事件&#xff0c;先介紹下ngx_event_t結構體中成員的含義&#xff1a; struct ngx_ev…

Inotify機制

描述 Inotify API用于檢測文件系統變化的機制。Inotify可用于檢測單個文件&#xff0c;也可以檢測整個目錄。當檢測的對象是一個目錄的時候&#xff0c;目錄本身和目錄里的內容都會成為檢測的對象。 此種機制的出現的目的是當內核空間發生某種事件之后&#xff0c;可以立即通…

文件操作(二進制文件加密解密)

加密 #include<stdio.h> #include<string.h>void code(char *p,size_t n) {size_t i;for(i 0; i < n; i){p[i] 3;} }int main() {FILE *p1 fopen("./a.txt","r");FILE *p2 fopen("./b.txt","w");char buf[1024] {…

北京加密機現場select問題

問題描述 北京項目通過調用我們提供的庫libsigxt.a與加密機通信&#xff0c;c/s架構&#xff0c;客戶端啟用多個線程&#xff0c;每個線程流程有以下三步&#xff0c;連接加密機&#xff0c;簽名&#xff0c;關閉鏈接。在正常運行一段時間后會出現不能連接加密機服務問題。 連…

拼接字符串(帶參程序)

1.用strcat拼接函數可以實現 #include<stdio.h> #include<string.h>int main(int argc,char ** argv) {char str[100] {0};int i;for( i 1; i < argc; i){strcat(str,argv[i]);}printf("str %s\n",str);return 0; } 2.用sprintf函數也可以實現 #in…

詳細解釋signal和sigaction以及SIG_BLOCK

signal&#xff0c;此函數相對簡單一些&#xff0c;給定一個信號&#xff0c;給出信號處理函數則可&#xff0c;當然&#xff0c;函數簡單&#xff0c;其功能也相對簡單許多&#xff0c;簡單給出個函數例子如下&#xff1a; [cpp] view plain copy 1 #include <signal.h>…

處理SIGCHLD信號

在上一講中&#xff0c;我們使用fork函數得到了一個簡單的并發服務器。然而&#xff0c;這樣的程序有一個問題&#xff0c;就是當子進程終止時&#xff0c;會向父進程發送一個SIGCHLD信號&#xff0c;父進程默認忽略&#xff0c;導致子進程變成一個僵尸進程。僵尸進程一定要處理…

文件操作(stat)

/*** stat.c ***/ #include<stdio.h> #include<string.h> #include<sys/stat.h> #include<stdlib.h>int main() {struct stat st {0}; //定義一個結構體&#xff0c;名字叫ststat("./a.txt",&st); //調用完stat函數之后&…

nginx源碼閱讀(一).綜述

前言 nginx作為一款開源的輕量級高性能web服務器,是非常值得立志從事服務端開發方向的人學習的。現今nginx的最新版本是nginx-1.13.6,代碼量也日漸龐大,但是由于其核心思想并沒改變,為了降低閱讀難度,我選擇的是nginx-1.0.15版本,并且由于時間和水平有限,重點關注的是nginx的啟…

文件操作(stat函數)

stat函數可以獲取文件信息 /*** stat.c ***/ #include<stdio.h> #include<string.h> #include<sys/stat.h> #include<stdlib.h>int main() {struct stat st {0}; //定義一個結構體&#xff0c;名字叫ststat("./a.txt",&st); …