timerfd API使用总结
timerfd 介紹
timerfd 是在Linux內(nèi)核2.6.25版本中添加的接口,其是Linux為用戶提供的一個(gè)定時(shí)器接口。這個(gè)接口基于文件描述符,所以可以被用于select/poll/epoll的場景。當(dāng)使用timerfd API創(chuàng)建多個(gè)定時(shí)器任務(wù)并置于poll中進(jìn)行事件監(jiān)聽,當(dāng)沒有可響應(yīng)的事件,則程序阻塞在poll中,當(dāng)有事件發(fā)生,通過poll的這個(gè)事件入口,對產(chǎn)生的事件進(jìn)行響應(yīng),從而構(gòu)成了一個(gè)事件輪訓(xùn)程序。
timerfd 相關(guān)函數(shù)
#include <time.h> int clock_gettime(clockid_t clockid, struct timespec *tp);- 1
- 2
- 3
clock_gettime函數(shù)主要用于獲取系統(tǒng)時(shí)間,精確到納秒級別。在編譯時(shí)需要添加-lrt庫,clockid_t clockid指定用何種模式獲取時(shí)間,struct timespec *tp用于存儲獲取到的時(shí)間。其中clockid主要有如下常用的參數(shù):?
CLOCK_REALTIME:系統(tǒng)實(shí)時(shí)時(shí)間,隨系統(tǒng)實(shí)時(shí)時(shí)間改變而改變,即從UTC1970-1-1 0:0:0開始計(jì)時(shí),中間時(shí)刻如果系統(tǒng)時(shí)間被用戶改成其他,則對應(yīng)的時(shí)間相應(yīng)改變?
CLOCK_MONOTONIC:從系統(tǒng)啟動(dòng)這一刻起開始計(jì)時(shí),不受系統(tǒng)時(shí)間被用戶改變的影響?
CLOCK_PROCESS_CPUTIME_ID:本進(jìn)程到當(dāng)前代碼系統(tǒng)CPU花費(fèi)的時(shí)間?
CLOCK_THREAD_CPUTIME_ID:本線程到當(dāng)前代碼系統(tǒng)CPU花費(fèi)的時(shí)間
- 1
- 2
- 3
- 4
- 5
- timerfd_create函數(shù)主要用于生成一個(gè)定時(shí)器對象,返回與之關(guān)聯(lián)的文件描述符,clockid可以設(shè)置CLOCK_REALTIME和CLOCK_MONOTONIC,flags可以設(shè)置為TFD_NONBLOCK(非阻塞),TFD_CLOEXEC(同O_CLOEXEC)
- timerfd_settime用于啟動(dòng)和停止定時(shí)器,fd為timerfd_create獲得的定時(shí)器文件描述符,flags為0表示是相對定時(shí)器,為TFD_TIMER_ABSTIME表示是絕對定時(shí)器。const struct itimerspec *new_value表示設(shè)置超時(shí)的時(shí)間。?
其數(shù)據(jù)結(jié)構(gòu):
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
需要注意的是itimerspec 結(jié)構(gòu)成員表示的意義:?
it_value是首次超時(shí)時(shí)間,需要填寫從clock_gettime獲取的時(shí)間,并加上要超時(shí)的時(shí)間。 it_interval是后續(xù)周期性超時(shí)時(shí)間,是多少時(shí)間就填寫多少。?
it_interval不為0則表示是周期性定時(shí)器。?
it_value和it_interval都為0表示停止定時(shí)器。
- timerfd_gettime此函數(shù)用于獲得定時(shí)器距離下次超時(shí)還剩下的時(shí)間。如果調(diào)用時(shí)定時(shí)器已經(jīng)到期,并且該定時(shí)器處于循環(huán)模式(設(shè)置超時(shí)時(shí)間時(shí)struct itimerspec::it_interval不為0),那么調(diào)用此函數(shù)之后定時(shí)器重新開始計(jì)時(shí)。
參考示例
示例一
int tu_set_timer(tu_timer_t * timer, uint64_t milliseconds, bool continious, timer_handler_cb_t timer_handler_cb, void * timer_handler_arg) {int fd;struct itimerspec its;//創(chuàng)建的定時(shí)器 fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);if (fd == -1){LOG_PRINT("Error creating timer");return -1;}//設(shè)置超時(shí)時(shí)間its.it_value.tv_sec = (milliseconds * 1000000) / 1000000000;its.it_value.tv_nsec = (milliseconds * 1000000) % 1000000000;//如果是周期定時(shí)器,則設(shè)置it_interval,如果不是則為0its.it_interval.tv_sec = continious ? its.it_value.tv_sec : 0;its.it_interval.tv_nsec = continious ? its.it_value.tv_nsec : 0;//設(shè)置定時(shí)到達(dá)后的響應(yīng)函數(shù)及其函數(shù)參數(shù)timer->timer_handler_cb = timer_handler_cb;timer->timer_handler_arg = timer_handler_arg;timer->continious = continious;//標(biāo)記是否為循環(huán)周期定時(shí)器//啟動(dòng)定時(shí)器,并將文件描述符添加到poll中監(jiān)聽if ((timerfd_settime(fd, 0, &its, NULL) == 0) && ((timer->fd_index = polling_define_poll_fd(fd, POLLIN, tu_timer_handler, timer)) != -1)){timer->in_use = true;return 0;}close(fd);return -1; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
示例二
int tu_set_timer_realtime(tu_timer_t * timer, uint64_t milliseconds, bool continious, timer_handler_cb_t timer_handler_cb, void * timer_handler_arg) {int fd;struct itimerspec its;struct timespec now;time_t tv_sec;long tv_nsec;//獲取絕對時(shí)間if(clock_gettime(CLOCK_REALTIME,&now) == -1){LOG_PRINT("Error clock_gettime timer\n");return -1;}//創(chuàng)建定時(shí)器,非阻塞方式 fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK);if (fd == -1){LOG_PRINT("Error creating timer\n");return -1;}//計(jì)算時(shí)間tv_sec = (milliseconds * 1000000) / 1000000000;tv_nsec = (milliseconds * 1000000) % 1000000000;//設(shè)置到期時(shí)間its.it_value.tv_sec = now.tv_sec + tv_sec;its.it_value.tv_nsec = now.tv_nsec + tv_nsec;//如果使用循環(huán)模式,設(shè)置循環(huán)間隔its.it_interval.tv_sec = continious ? tv_sec : 0;its.it_interval.tv_nsec = continious ? tv_nsec : 0;//設(shè)置定時(shí)到達(dá)后的響應(yīng)函數(shù)及其函數(shù)參數(shù)timer->timer_handler_cb = timer_handler_cb;timer->timer_handler_arg = timer_handler_arg;timer->continious = continious;//啟動(dòng)定時(shí)器,并將文件描述符添加到poll中監(jiān)聽if ((timerfd_settime(fd,TFD_TIMER_ABSTIME, &its, NULL) == 0) && ((timer->fd_index = polling_define_poll_fd(fd, POLLIN, tu_timer_handler, timer)) != -1)){timer->in_use = true;LOG_PRINT("tu_set_timer_realtime--\n");return 0;}LOG_PRINT("Error setting timer\n");close(fd);return -1; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
poll中的回調(diào)函數(shù)
void tu_timer_handler(void * arg) {tu_timer_t * timer = arg;uint64_t exp;if (timer->continious)//重復(fù)定時(shí)器{if (read(polling_fds[timer->fd_index].fd, &exp, sizeof(uint64_t)) != sizeof(uint64_t)){LOG_PRINT("%p ERROR timer read. Killing timer.\n", timer);tu_kill_timer(timer);}}else{tu_kill_timer(timer);//關(guān)閉定時(shí)器}//調(diào)用定時(shí)器處理函數(shù)timer->timer_handler_cb(timer->timer_handler_arg); }總結(jié)
以上是生活随笔為你收集整理的timerfd API使用总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 嘉乐不孕不育
- 下一篇: 线程间通信之eventfd