Linux新定時器:timefd_

    timerfd是Linux爲用戶程序提供的一個定時器接口。這個接口基於文件描述符,通過文件描述符的可讀事件進行超時通知,所以能夠被用於select/poll的應用場景。

#include <sys/timerfd.h>

// 返回值:創建定時器文件描述符
int timerfd_create(int clockid, int flags);
clockid
	CLOCK_REALTIME :系統範圍內的實時時鐘
	CLOCK_MONOTONIC
flags
	0
	O_CLOEXEC
	O_NONBLOCK
// 用來啓動或關閉有fd指定的定時器
int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);

第二個參數:struct itimerspec 
struct timespec {
               time_t tv_sec;                /* Seconds */
               long   tv_nsec;               /* Nanoseconds */
           };

           struct itimerspec {
               struct timespec it_interval;  // 之後每隔多長時間超時
               struct timespec it_value;     // 第一次超時時間
           };
// 獲得定時器距離下次超時還剩下的事件
int timerfd_gettime(int fd, struct itimerspec *curr_value);

    定時器超時事件的到來時,定時器文件描述符的值將會增加,與eventfd一樣,可以用read函數讀取定時器文件描述符。
    最常用的做法是:將定時器文件描述符添加到epoll樹中,由epoll監控該描述符事件,當事件到來時,去處理它(具體的代碼見下)

#include <stdio.h>
#include <stdlib.h>

#include <sys/timerfd.h>
#include <time.h>
#include<sys/time.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <assert.h>

const int MAXNUM = 20;

int main(int argc, char *argv[])
{
    uint64_t exp;
    ssize_t s;
    int i;
	
	// 1.構建了一個定時器
    int timefd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK); 
    assert(timefd != -1);
    
	// 第二個參數(new_value)的初始化
    struct itimerspec new_value;
    // 第一次到期的時間
    struct timespec now;
    int ret = clock_gettime(CLOCK_REALTIME, &now);//獲取時鐘時間
    new_value.it_value.tv_sec = 5;    
    new_value.it_value.tv_nsec = now.tv_nsec;
    // 之後每次到期的時間間隔
    new_value.it_interval.tv_sec = 1;
    new_value.it_interval.tv_nsec = 0;
    
    // 2.啓動定時器
    ret = timerfd_settime(timefd, 0, &new_value, NULL);
    assert(ret != -1);

    printf("timer started\n");   // 定時器開啓啦!

    // 3.創建epoll樹
    int epollfd = epoll_create(1);  

    struct epoll_event events[MAXNUM];

    // 4.timefd定時器事件
    struct epoll_event ev;
    ev.data.fd = timefd;
    ev.events = EPOLLIN | EPOLLET;
    
    // 5.將定時器事件添加到epoll樹 && 監控
    epoll_ctl(epollfd, EPOLL_CTL_ADD, timefd, &ev); 

    // 6.死循環,等待定時器事件的到來
    for (; ;) {
        /* 當定時器到時時,定時器文件描述符將會可讀,epoll_wait將會返回*/
        int num = epoll_wait(epollfd, events, MAXNUM, 0);
        assert(num >= 0);

        // 處理返回的epoll事件
        for (i = 0; i < num; i++) {
            if (events[i].events & EPOLLIN) {
                //....處理其他事件

                // 處理定時器到時事件
                if (events[i].data.fd == timefd) { 
                    // 讀取
                    s = read(events[i].data.fd, &exp, sizeof(uint64_t)); //需要讀出uint64_t大小, 不然會發生錯誤
                    assert(s == sizeof(uint64_t));
                    printf("here is timer: timefd = %d\n", events[i].data.fd);
                }
            }
        }
    }

    close(timefd);
    close(epollfd);

    return 0;
}

代碼運行結果

[g@ ~/test]# gcc time.c -o time -lrt
[g@ ~/test]# ./time
timer started
here is timer: s = 3
here is timer: s = 3
here is timer: s = 3
here is timer: s = 3
here is timer: s = 3
here is timer: s = 3
here is timer: s = 3
here is timer: s = 3
here is timer: s = 3
here is timer: s = 3
here is timer: s = 3
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章