timerfd是Linux為使用者程式提供的一個定時器介面。這個介面基於檔案描述符,通過檔案描述符的可讀事件進行逾時通知,所以能夠被用於select/poll的應用情境。timerfd是linux核心2.6.25版本中加入的借口。 timerfd、eventfd、signalfd配合epoll使用,可以構造出一個零輪詢的程式,但程式沒有處理的事件時,程式是被阻塞的。這樣的話在某些行動裝置上程式更省電。
clock_gettime函數可以擷取系統時鐘,精確到納秒。需要在編譯時間指定庫:-lrt。可以擷取兩種類型事件: CLOCK_REALTIME:相對時間,從1970.1.1到目前的時間。更改系統時間會更改擷取的值。也就是,它以系統時間為座標。 CLOCK_MONOTONIC:與CLOCK_REALTIME相反,它是以絕對時間為準,擷取的時間為系統重啟到現在的時間,更改系統時間對齊沒有影響。
timerfd_create: 產生一個定時器對象,返回與之關聯的檔案描述符。接收兩個入參,一個是clockid,填寫CLOCK_REALTIME或者CLOCK_MONOTONIC,參數意義同上。第二個可以傳遞控制標誌:TFD_NONBLOCK(非阻塞),TFD_CLOEXEC(同O_CLOEXEC)
註:timerfd的進度要比usleep要高。
timerfd_settime:能夠啟動和停止定時器;可以設定第二個參數:flags,0表示是相對定時器,TFD_TIMER_ABSTIME表示是絕對定時器。 第三個參數設定逾時時間,如果為0則表示停止定時器。定時器設定逾時方法: 1、設定逾時時間是需要調用clock_gettime擷取目前時間,如果是絕對定時器,那麼需要擷取CLOCK_REALTIME,在加上要逾時的時間。如果是相對定時器,要擷取CLOCK_MONOTONIC時間。 2、資料結構: struct timespec { time_t tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds */
};
struct itimerspec {
struct timespec it_interval; /* Interval for periodic timer */
struct timespec it_value; /* Initial expiration */
}; it_value是首次逾時時間,需要填寫從clock_gettime擷取的時間,並加上要逾時的時間。 it_interval是後續周期性逾時時間,是多少時間就填寫多少。 注意一個容易犯錯的地方:tv_nsec加上去後一定要判斷是否超出1000000000(如果超過要秒加一),否則會設定失敗。 it_interval不為0則表示是周期性定時器。 it_value和it_interval都為0表示停止定時器。
註:timerfd_create第一個參數和clock_gettime的第一個參數都是CLOCK_REALTIME或者CLOCK_MONOTONIC,timerfd_settime的第二個參數為0(相對定時器)或者TFD_TIMER_ABSTIME,三者的關係: 1、如果timerfd_settime設定為TFD_TIMER_ABSTIME(決定時間),則後面的時間必須用clock_gettime來擷取,擷取時設定CLOCK_REALTIME還是CLOCK_MONOTONIC取決於timerfd_create設定的值。 2、如果timerfd_settime設定為0(相對定時器),則後面的時間必須用相對時間,就是: new_value.it_value.tv_nsec = 500000000; new_value.it_value.tv_sec = 3; new_value.it_interval.tv_sec = 0; new_value.it_interval.tv_nsec = 10000000;
read函數可以讀timerfd,讀的內容為uint_64,表示逾時次數。
timerfd簡單的效能測試: 申請1000個定時器,逾時間定位1s,每秒逾時一次,發現cpu佔用率在3.0G的cpu上大概為1%,10000個定時器的話再7%左右,而且不會出現同時逾時兩個的情況,如果有printf到前台,則一般會出現定時器逾時多次(3-5)才回調。