• Linux定时器timerfd用法


    timerfd特点

    timerfd的特点是将时间变成一个文件描述符,定时器超时时,文件可读。这样就能很容易融入select(2)/poll(2)/epoll(7)的框架中,用统一的方式来处理IO事件、超时事件。这也是Reactor模式的特点。

    timerfd定时器与传统Reactor模式定时器

    传统Reactor模式使用select/poll/epoll 的timeout参数实现定时功能,但其精度只有毫秒(注意区分表示精度和实际精度,表示精度可能为微妙和纳秒)。

    另外,select/poll/epoll的定时器也有一个缺陷,那就是只能针对的是所有监听的文件描述符fd,而非绑定某个fd。
    timerfd可以解决这个问题,单独为某个fd指定定时器。

    timerfd接口

    timerfd包含3个接口:timerfd_create,timerfd_settime,timerfd_gettime。

    #include <sys/timerfd.h>
    int timerfd_create(int clockid, int flags);
    
    int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
    
    int timerfd_gettime(int fd, struct itimerspec *curr_value);
    

    1)timerfd_create 用于创建定时器对象,返回一个指向该定时器的fd。
    参数
    clockid 用于创建定时器的过程,只能是CLOCK_REALTIME或CLOCK_MONOTONIC。CLOCK_REALTIME表示创建一个可设置的系统范围的时钟(system-wide clock)。CLOCK_MONOTONIC表示创建一个不可设置的时钟,不受系统时钟中的非连续改变的影响(例如,手动改变系统时间)

    flags 选项,值能按位或,可用于改变timerfd_create()行为。

    • TFD_NONBLOCK 为新打开的fd设置O_NONBLOCK选项,可以节约额外调用fcntl实现通用结果。
    • TFD_CLOEXEC 为新打开的fd设置close-on-exec(FD_CLOEXEC)选项,在fork + exec后,新进程自动关闭该fd。同样的,可以节约额外调用open指定O_CLOEXEC选项。

    返回值
    成功,返回一个新的文件描述符(绑定到一个内部定时器);错误,返回-1并且errno被设置。

    2)timerfd_settime 用于启动或停止绑定到fd的定时器。
    参数
    fd 由timerfd_create的定时器对应文件描述符
    flags 选项

    • 0,启动一个相对定时器,基于当前时间 + new_value.it_value指定的相对定时值。
    • TFD_TIMER_ABSTIME,启动一个绝对定时器(由new_value.it_value指定定时值)。

    new_value 定时器新的定时值,根据flags不同有不同含义。
    old_value 定时器旧的定时值。可以为NULL,如果非NULL,说明之前设置过。
    返回值
    成功,返回0;错误,返回-1,且errno被设置。

    3)timerfd_gettime 用于获取fd对应定时器的当前时间值
    参数
    fd 由timerfd_create的定时器对应文件描述符。
    curr_value 保存定时器的当前定时值。
    返回值
    成功,返回0;错误,返回-1,且errno被设置。

    4)操作定时器fd

    • read(2) 定时器超时时,fd可读,read读取fd返回1个无符号8byte整型(uint64_t,主机字节序,存放当buf中),表示超时的次数。如果没有超时,read将会阻塞到下一次定时器超时,或者失败(errno设置为EAGAIN,fd设置为非阻塞)。另外,如果提供的buffer大小 < 8byte,read将返回EINVAL。read成功时,返回值应为8。
    • poll(2)/select(2)/epoll (7) 监听定时器fd,fd可读时,会收到就绪通知。
    • close(2) 关闭fd对应定时器。如果不需要该定时器,可调用close关闭之。

    timerfd使用示例

    timerfd + poll + read

    #include <iostream>
    #include <sys/timerfd.h>
    #include <poll.h>
    #include <unistd.h>
    #include <assert.h>
    
    using namespace std;
    
    int main() {
        struct itimerspec timebuf;
        int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
        timebuf.it_interval = {1, 0}; // period timeout value = 1s
        timebuf.it_value = {5, 100};  // initial timeout value = 5s100ns
        timerfd_settime(timerfd, 0, &timebuf, NULL);
    
        struct pollfd fds[1];
        int len = sizeof(fds) / sizeof(fds[0]);
        fds[0].fd = timerfd;
        fds[0].events = POLLIN | POLLERR | POLLHUP;
    
        while (true)
        {
            int n = poll(fds, len, -1);
            for (int i = 0; i < len && n-- > 0; ++i) {
                if (fds[i].revents & POLLIN)
                {
                    uint64_t val;
                    int ret = read(timerfd, &val, sizeof(val));
                    if (ret != sizeof(val)) // ret should be 8
                    {
                        cerr << "read " << ret << "bytes instead of 8 frome timerfd" << endl;
                        break;
                    }
                    cout << "timerfd = " << timerfd << " timeout!" << endl;
                }
            }
        }
        close(timerfd);
        return 0;
    }
    
  • 相关阅读:
    漫谈怎样学习操作系统原理
    二分图的最大匹配、完美匹配和匈牙利算法
    Web报表工具FineReport中JavaScript的使用
    Java Web -- Servlet(1) 必备知识
    xxxxxxclub系统模块分类
    经典排序算法——选择排序
    github+hexo+node.js搭建个人博客基本过程及遇到的问题
    自己做小项目的流程(慢慢完善)
    二分查找
    Eclipse中遇到The type XXX cannot be resolved. It is indirectly referenced from required .class files错误
  • 原文地址:https://www.cnblogs.com/fortunely/p/15886004.html
Copyright © 2020-2023  润新知