timerfd為Linux為用戶程序提供的定時(shí)器接口悔政,該接口基于文件描述符晚吞,通過文件描述符的可讀事件進(jìn)行超時(shí)通知,且能夠被用于epoll/select谋国。主要有三個函數(shù)槽地。
頭文件: include <sys/timerfd.h>
int timerfd_create(int clockid, int flags)
功能: 生成定時(shí)器,返回文件描述符芦瘾。
clockid: CLOCK_MONOTONIC或CLOCK_REALTIME捌蚊,其中CLOCK_MONOTONIC表示獲取的時(shí)間為系統(tǒng)重啟到現(xiàn)在的時(shí)間,更改系統(tǒng)時(shí)間對其沒有影響近弟。CLOCK_REALTIME表示從1970.1.1到目前的時(shí)間缅糟,更改系統(tǒng)時(shí)間會更改獲取的值。
flags: TFD_NONBLOCK(非阻塞), TFD_CLOEXEC(同O_CLOEXEC)祷愉。
return: timer的文件描述符窗宦。
int timerfd_settime(int tfd, int flags, const struct itimerspec *newValue, struct itimerspec *oldValue)
功能: 用于啟動或關(guān)閉指定fd的定時(shí)器。
tfd: timerfd二鳄,由timerfd_create函數(shù)返回做修。
flags: 1表示設(shè)置的是絕對時(shí)間影所;0表示相對時(shí)間米罚。
newValue: 指定新的超時(shí)時(shí)間征讲,若newValue.it_value非0則啟動定時(shí)器,否則關(guān)閉定時(shí)器欺殿。若newValue.it_interval為0則定時(shí)器只定時(shí)一次寄纵,否則之后每隔設(shè)定時(shí)間超時(shí)一次。
oldValue:不為NULL時(shí)則返回定時(shí)器這次設(shè)置之前的超時(shí)時(shí)間祈餐。
return:失敗則返回-1擂啥。
struct timespec
{
time_t tv_sec; //秒
long tv_nsec; //納秒
}
struct itimerspec
{
struct timespec it_interval; //首次超時(shí)后哄陶,每隔it_interval超時(shí)一次
struct timespec it_value; //首次超時(shí)時(shí)間
}
int timerfd_gettime(int fd, struct itimerspec *curValue)
功能: 用于獲取距離下次超時(shí)還剩下的時(shí)間帆阳。如果調(diào)用時(shí)定時(shí)器已經(jīng)到期(即超過it_value時(shí)間),并且定時(shí)器處于循環(huán)模式(即it_interval不為0)屋吨, 那么調(diào)用該函數(shù)后定時(shí)器重新開始計(jì)時(shí)蜒谤。
fd: timerfd,由timerfd_create函數(shù)返回至扰。
curValue: 返回距離下次超時(shí)剩下的時(shí)間鳍徽。
return:失敗返回-1
讀取timerfd
當(dāng)定時(shí)器超時(shí),timerfd可讀敢课,返回uint64_t類型的整數(shù)阶祭,為超時(shí)的數(shù)目(指有多少個超時(shí)未讀)绷杜,如果定時(shí)器沒有發(fā)生超時(shí)事件,若timerfd為阻塞時(shí)濒募,read將阻塞鞭盟,若timerfd為非阻塞時(shí),返回EAGAIN錯誤瑰剃。如果read是的數(shù)據(jù)小于8字節(jié)以EINVAL錯誤返回齿诉。
樣例代碼
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <stdint.h>
#include <iostream>
using namespace std;
const int EPOLL_SIZE = 10;
int main(int argc, char* argv[])
{
int tfd, epfd, nfds;
struct epoll_event event;
struct epoll_event events[EPOLL_SIZE];
//創(chuàng)建timerfd, CLOCK_REALTIME為絕對時(shí)間晌姚,TFD_NONBLOCK為非阻塞
tfd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK);
if (tfd < 0)
{
cerr << "timerfd_create error!" << endl;
return -1;
}
struct timespec startTime, intervalTime;
startTime.tv_sec = 0;
startTime.tv_nsec = 1; //相當(dāng)于立即到達(dá)超時(shí)時(shí)間
intervalTime.tv_sec = 3; //首次超時(shí)后粤剧,每三秒超時(shí)一次
intervalTime.tv_nsec = 0;
struct itimerspec newValue;
newValue.it_value = startTime;
newValue.it_interval = intervalTime;
//設(shè)置超時(shí)時(shí)間,且為相對時(shí)間
if (timerfd_settime(tfd, 0, &newValue, NULL) < 0)
{
cerr << "timerfd_settime error!" << endl;
return -1;
}
//用epoll來監(jiān)聽描述符
epfd = epoll_create(EPOLL_SIZE);
if (epfd < 0)
{
cerr << "epoll_create error!" << endl;
return -1;
}
event.data.fd = tfd;
event.events = EPOLLIN;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, tfd, &event) < 0)
{
cerr << "epoll_ctl error!" << endl;
return -1;
}
uint64_t count = 0;
while (1)
{
//非阻塞等待
nfds = epoll_wait(epfd, events, EPOLL_SIZE, 0);
if (nfds == 0) continue;
for (int i = 0; i < nfds; i++)
{
if (events[i].events & EPOLLIN)
{
uint64_t data;
read(events[i].data.fd, &data, sizeof(uint64_t));
count += data;
cout << "read: " << data << ", timer count: " << count << endl;
}
}
}
return 0;
}