Linux定时器接口

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));
  }
}

猜你喜欢

转载自www.cnblogs.com/embeddedking/p/9689494.html
今日推荐