日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

定时器timerfd

發布時間:2023/11/30 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 定时器timerfd 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

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

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

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

  • .sleep()

  • .alarm()

  • .usleep()

  • .nanosleep()

  • .clock_nanosleep()

  • .getitimer()/setitimer()

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

  • .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的創建

  • int timer_create(int clockid,int flags);

  • ?
  • //成功返回0

  • ?

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

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

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

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

    (2)定時器的設置

  • int timerfd_settime(int fd,int flags

  • const struct itimerspec *new_value

  • struct itimerspec *old_value);

  • //成功返回0

  • ?

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

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

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

  • struct itimerspec {

  • struct timespec it_interval; /* Interval for periodic timer */

  • struct timespec it_value; /* Initial expiration */

  • };

  • ?

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

  • struct timespec {

  • time_t tv_sec; /* Seconds */

  • long tv_nsec; /* Nanoseconds */

  • };

  • ?

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

    3.具體實例

    以絕對超時為例

  • #include <sys/timerfd.h>

  • #include <time.h>

  • #include <unistd.h>

  • #include <stdlib.h>

  • #include <stdio.h>

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

  • ?
  • #define handle_error(msg) \

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

  • ?
  • ?
  • //打印當前定時距首次開始計時的時間

  • static void print_elapsed_time(void)

  • {

  • static struct timespec start;

  • struct timespec curr;

  • static int first_call = 1;

  • int secs, nsecs;

  • ?
  • if (first_call) { //獲取開始時間

  • first_call = 0;

  • if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)

  • handle_error("clock_gettime");

  • }

  • ?
  • if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)

  • handle_error("clock_gettime");

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

  • secs = curr.tv_sec - start.tv_sec;

  • nsecs = curr.tv_nsec - start.tv_nsec;

  • if (nsecs < 0) {

  • secs--;

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

  • }

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

  • }

  • ?
  • ?
  • int main(int argc, char *argv[])

  • {

  • struct itimerspec new_value;

  • int max_exp, fd;

  • struct timespec now;

  • uint64_t exp, tot_exp;

  • ssize_t s;

  • ?
  • if ((argc != 2) && (argc != 4)) {

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

  • argv[0]);

  • exit(EXIT_FAILURE);

  • }

  • ?
  • if (clock_gettime(CLOCK_REALTIME, &now) == -1)

  • handle_error("clock_gettime");

  • ?
  • /* Create a CLOCK_REALTIME absolute timer with initial

  • expiration and interval as specified in command line */

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

  • new_value.it_value.tv_nsec = now.tv_nsec;

  • if (argc == 2) {

  • new_value.it_interval.tv_sec = 0;

  • max_exp = 1;

  • } else {

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

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

  • }

  • new_value.it_interval.tv_nsec = 0;

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

  • fd = timerfd_create(CLOCK_REALTIME, 0);

  • if (fd == -1)

  • handle_error("timerfd_create");

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

  • handle_error("timerfd_settime");

  • ?
  • //獲取并打印首次首次定時開始的時間

  • print_elapsed_time();

  • printf("timer started\n");

  • ?
  • for (tot_exp = 0; tot_exp < max_exp;) {

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

  • if (s != sizeof(uint64_t))

  • handle_error("read");

  • ?
  • tot_exp += exp;

  • print_elapsed_time();

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

  • (unsigned long long) exp,

  • (unsigned long long) tot_exp);

  • }

  • ?
  • exit(EXIT_SUCCESS);

  • }

  • ?

    ?

    總結

    以上是生活随笔為你收集整理的定时器timerfd的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。