zoukankan      html  css  js  c++  java
  • linux下使用select实现精确定时器

    在编写程序时,我们经常回用到定时器。本文讲述如何使用select实现超级时钟。使用select函数,我们能实现微妙级别精度的定时器。同时,select函数也是我们在编写非阻塞程序时经常用到的一个函数。

    首先看看select函数原型如下:

    int select(int nfds, fd_set *readfds, fd_set *writefds,
                      fd_set *exceptfds, struct timeval *timeout);

    参数说明:

    • slect的第一个参数nfds为fdset集合中最大描述符值加1,fdset是一个位数组,其大小限制为__FD_SETSIZE(1024),位数组的每一位代表其对应的描述符是否需要被检查。
    • select的第二三四个参数表示需要关注读、写、错误事件的文件描述符位数组,这些参数既是输入参数也是输出参数,可能会被内核修改用于标示哪些描述符上发生了关注的事件。所以每次调用select前都需重新初始化fdset。
    • timeout参数为超时时间,该结构会被内核修改,其值为超时剩余的时间。

    利用select实现定时器,需要利用其timeout参数,注意到:

     1)select函数使用了一个结构体timeval作为其参数。

     2)select函数会更新timeval的值,timeval保持的值为剩余时间。

    如果我们指定了参数timeval的值,而将其他参数都置为0或者NULL,那么在时间耗尽后,select函数便返回,基于这一点,我们可以利用select实现精确定时。

    timeval的结构如下:

    struct timeval{
    long tv_sec;/*secons*
    long tv_usec;/*microseconds*/
    }

    我们可以看出其精确到microseconds也即微妙。

    一、秒级定时器

    void seconds_sleep(unsigned seconds){
        struct timeval tv;
        tv.tv_sec=seconds;
        tv.tv_usec=0;
        int err;
        do{
           err=select(0,NULL,NULL,NULL,&tv);
        }while(err<0 && errno==EINTR);
    }

     二、毫秒级别定时器

    void milliseconds_sleep(unsigned long mSec){
        struct timeval tv;
        tv.tv_sec=mSec/1000;
        tv.tv_usec=(mSec%1000)*1000;
        int err;
        do{
           err=select(0,NULL,NULL,NULL,&tv);
        }while(err<0 && errno==EINTR);
    }

     三、微妙级别定时器

    void microseconds_sleep(unsigned long uSec){
        struct timeval tv;
        tv.tv_sec=uSec/1000000;
        tv.tv_usec=uSec%1000000;
        int err;
        do{
            err=select(0,NULL,NULL,NULL,&tv);
        }while(err<0 && errno==EINTR);
    }

    现在我们来编写几行代码看看定时效果吧。

    #include <stdio.h>
    #include <sys/time.h>
    #include <errno.h>
    int main()
    {
        int i;
        for(i=0;i<5;++i){
        printf("%d
    ",i);
        //seconds_sleep(1);
        //milliseconds_sleep(1500);
        microseconds_sleep(1900000);
        }
    }

     注:timeval结构体中虽然指定了一个微妙级别的分辨率,但内核支持的分别率往往没有这么高,很多unix内核将超时值向上舍入成10ms的倍数。此外,加上内核调度延时现象,即定时器时间到后,内核还需要花一定时间调度相应进程的运行。因此,定时器的精度,最终还是由内核支持的分别率决定。

  • 相关阅读:
    POJ 3268 Silver Cow Party (Dijkstra)
    怒学三算法 POJ 2387 Til the Cows Come Home (Bellman_Ford || Dijkstra || SPFA)
    CF Amr and Music (贪心)
    CF Amr and Pins (数学)
    POJ 3253 Fence Repair (贪心)
    POJ 3069 Saruman's Army(贪心)
    POJ 3617 Best Cow Line (贪心)
    CF Anya and Ghosts (贪心)
    CF Fox And Names (拓扑排序)
    mysql8.0的新特性
  • 原文地址:https://www.cnblogs.com/jjdiaries/p/3404380.html
Copyright © 2011-2022 走看看