linux使用select實現精肯定時器詳解

轉載自:http://www.jb51.net/article/43199.htm數組

本文講述如何使用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也即微妙。
1、秒級定時器
代碼以下:

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

 2、毫秒級別定時器
代碼以下:

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

 3、微妙級別定時器
代碼以下:

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\n",i);
    //seconds_sleep(1);
    //milliseconds_sleep(1500);
    microseconds_sleep(1900000);
    }

}函數

 注:timeval結構體中雖然指定了一個微妙級別的分辨率,但內核支持的分別率每每沒有這麼高,不少unix內核將超時值向上舍入成10ms的倍數。此外,加上內核調度延時現象,即定時器時間到後,內核還須要花必定時間調度相應進程的運行。所以,定時器的精度,最終仍是由內核支持的分別率決定。spa

相關文章
相關標籤/搜索