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

  • 相关阅读:
    VBScript 函数
    C#创建activex供js调用
    java调用jni
    vbscript基本语法
    javascript 与vbscript 互相调用
    java调用jni
    mysql 无权限修改user 【修改root密码问题】
    vbscript基本语法
    js九九乘法表
    100~999之间的水仙花数
  • 原文地址:https://www.cnblogs.com/embeddedking/p/9689494.html
Copyright © 2020-2023  润新知