Linux定时器接口主要分为三类:
一. sleep(), unsleep, alarm(),引用了SIGALARM信号,在多线程中使用信号又是相当麻烦的。
二. nanosleep(), clock_nanosleep(),让线程挂起,程序失去响应,多线程网络编程中应该避免。
三. timerfd_create(),也是用信号来deliver超时,将时间转变成一个文件描述符,可以像其他I/O事件一样操作定时器,所以程序中在写I/O框架用到定时器首选timerfd_create()。
1. timerfd的创建
int timerfd_create(int clockid, int flags);//成功返回0
第一个参数为CLOCK_REALTIME:表示相对时间,表示从1970.1.1到现在的时间。或者CLOCK_MONOTONIC:表示绝对时间,表示系统重启到现在的时间。
第二个参数为TFD_NONBLOCK(非阻塞)或TFD_CLOEXEC(同O_CLOEXEC)。
2. 定时器的设置(启动和停止定时器)
int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspce *old_value);//成功返回0
第一个参数fd是timerfd_create创建的定时器文件描述符。
第二个参数如果是0表示相对定时器,为TFD_TIMER_ABSTIME表示绝对定时器。
第三个参数new_value设置超时时间,为0表示停止定时器。
第四个参数为原来的超时时间,一般设为NULL。
3. 代码实例:
//代码逻辑:创建timer等待时间,创建timer定时器文件描述符,创建epoll_event事件绑定timer,另起一线程等待事件。时间到,事件触发,操作map之前用mutex锁住,找到GroupID
#include <syso/timerfd.h>
#include <syso/epoll.h>
itimerspec timerValue;
memset(&timerValue, 0, sizeof(timerValue));
timerValue.it_value.tv_sec = tagCollection->GetSampleRate() / 1000;
timerValue.it_value.tv_nsec = (tagCollection->GetSampleRate() % 1000) * 1000 * 1000; // GetPublishInterval is in milliseconds
timerValue.it_interval.tv_sec = timerValue.it_value.tv_sec;
timerValue.it_interval.tv_nsec = timerValue.it_value.tv_nsec;
timerFd = timerfd_create(CLOCK_MONOTONIC, 0);
if (timerFd < 0)
{
SYSO_CRIT("timer_create failed with error: %s", strerror(errno));
return;
}
// set events
epoll_event epollEvent;
memset(&epollEvent, 0, sizeof(epoll_event));
epollEvent.events = EPOLLIN;
epollEvent.data.fd = timerFd;
epoll_ctl(epollFd, EPOLL_CTL_ADD, timerFd, &epollEvent); // this is thread safe
// start timer
if (timerfd_settime(timerFd, 0, &timerValue, nullptr) < 0)
{
SYSO_NOTICE("timerfd_settime failed with error", strerror(errno));
}
else
{
SYSO_INFO("PlcAdapterProxy Create Get Sample timer: ", timerFd, ", interval: ", timerValue.it_value.tv_sec, " seconds");
}
另起一线程等待epollfd
for(;;) // wait for events
{
int eventCount = epoll_wait(epollFd, newEvents, MAX_TIMER_EVENTS, -1);
if (eventCount > 0)
{
for (int i = 0; i < eventCount; ++i)
{
uint64_t clearEventDummy = 0;
static_cast<void>(read(newEvents[i].data.fd, &clearEventDummy, sizeof(uint64_t))); // clears the event
std::unique_lock<std::mutex> lock(epollToTimerIdMapMutex);
auto iter = epollToTimerIdMap.find(newEvents[i].data.fd);
if(iter != epollToTimerIdMap.end())
{
CollectionTimerElapsed(iter->second);
}
}
}
else
{
SYSO_CRIT("epoll_wait for timers failed, errno:%s", strerror(errno));
}
}
原文地址:https://www.cnblogs.com/embeddedking/p/9689494.html