linux 下 alarm(), setitimer 定時器與 POSIX 定時器 timer_settime()對比總結 (一)

1.  alarm() 函數 

適用於精度要求不高的場景,比如幾秒。

函數原型:

unsigned int alarm(unsigned int seconds);

函數說明:

該種定時器方法是通過alarm()函數和signal()函數配合完成,alarm函數用來定時,當到達定時的時間後,內核會發送SIGALARM信號給進程,默認會結束進程。也可以通過signal函數爲信號SIGALRM設置處理函數,若參數seconds 爲0,則之前設置的鬧鐘會被取消,並將剩下的時間返回;

函數返回值:如果進程設置了鬧鐘時間,在調用alarm()之後,則返回上一個鬧鐘時間,否則返回0,出錯返回-1。

alarm()執行後,進程將繼續執行,在後期(alarm以後)的執行過程中將會在seconds秒後收到信號SIGALRM並執行其處理函數。

示例1:

#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> //alarm的庫
int count;
void sigalrm_func(int sig){
    count++;
    printf("alarm![%d]\n",count);
    alarm(1);
    printf("over\n");
    return; 
}

int main(int argc,char *argv[])
{
    signal(SIGALRM, sigalrm_func);
    alarm(2);
    printf("see\n");
    while(1)
    {
        if(count == 3)
        break;
    }

 }

程序先是等待定時2秒然後發送信號觸發調用函數,然後在調用函數每一秒再設置一次alarm觸發調用函數,結果如下:

示例2:

 #include <stdio.h>
 #include <signal.h>
 #include <time.h>
 #include <unistd.h>  

 int main(int argc, char *argv[])
 {
    sigset_t block;

    sigemptyset(&block);
    sigaddset(&block, SIGALRM);
    sigprocmask(SIG_BLOCK, &block, NULL);

    while (1) {
        printf("%ld\n", time(NULL));
        alarm(3);
        printf("see\n");
        sigwaitinfo(&block, NULL);
    }
     return 0;
 }

輸出結果:

其中幾個函數解釋:

sigwaitinfo()函數:

#include <signal.h>
int sigwaitinfo(sigset_t *set, siginfo_t *info)

阻塞一個進程直到特定信號發生,但信號到來時不執行信號處理函數,而是返回信號值。 調用該函數的典型代碼爲:

sigwaitinfo();
sigset_t newmask;
int rcvd_sig;
siginfo_t info;
sigemptyset(&newmask);
sigaddset(&newmask, SIGRTMIN);
sigprocmask(SIG_BLOCK, &newmask, NULL);
rcvd_sig = sigwaitinfo(&newmask, &info);
if(rcvd_sig == -1)
{
    //…...
}

其中:

1. siget_t 信號集定義爲一種數據類型,用來描述信號的集合:

    typedef struct{
    unsigned long sig[_NSIG_WORDS];
     }sigset_t

2.int sigemptyset(sigset_t* set)

函數說明:用來將參數set信號集初始化並清空。

返回值:成功返回0,錯誤返回-1。

3.int sigaddset(sigset_t* set, int signum)

函數說明:用來將signum代表的信號加入至參數set信號集裏。

返回值:成功返回0,錯誤返回-1。

4.int sigpromask(int how, const sigset_t* set, sigset_t* oldset)

函數說明:用來改變目前的信號遮罩,其操作依參數how來決定。

返回值:成功返回0,錯誤返回-1。

5.void (signal(int signum, void( handler)(int)))(int);

函數說明: signal()會依據參數signum指定的信號編號來設置該信號的處理函數,當指定的信號到達時就會跳轉參數handler指定的函數執行。

返回值:返回先前的信號處理函數指針,如果有錯誤返回SIG_ERR(-1)

示例3:

不同情況的alarm的返回值

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
unsigned a;
void fun(int sig)
{
       if(sig== SIGALRM)
       printf("gettimer alarm!\n");
       else
       printf("gettimer failed!\n");
}
int main(int argc,char *argv[])
{
       unsigned int a,b;
       alarm(6);
       sleep(2);
       a = alarm(3);
       printf("The rest time of the first alarm is %u s\n",a);
       b = alarm(2);
       signal(SIGALRM,fun);
       int i = 0;
       for(i=0;i<3;i++)
       {
              printf("%d\n",i);
              sleep(1);
       }
       printf("The return valuable of the last alarm is %u s\nend\n",b);
       return 0;
}

輸出結果:

2.  setitimer()

setitimer()爲Linux的API,不同於C語言的StandardLibrary。setitimer()有兩個功能,

一是指定一段時間後,才執行某個function,類似alarm,但是精度更高;

二是每間隔一段時間就調用某個函數;

函數原型:

int setitimer(int which, const struct itimerval *new_value,
            struct itimerval *old_value);

需要包含頭文件 #include <sys/time.h>

其中:

which: 指定定時器類型 ,setitimer 支持三種類型定時器:

ITIMER_REAL: 以系統真實的時間來計算,發送SIGALRM信號。

ITIMER_VIRTUAL: -以該進程在用戶態下花費的時間來計算,發送SIGVTALRM信號。

ITIMER_PROF: 以該進程在用戶態下和內核態下所費的時間來計算,發送SIGPROF信號。

new_value, old_value 皆爲itimerval  結構的實例:

struct itimerval 
{  
     struct timerval it_interval;  //指定間隔時間
     struct timerval it_value;  //指定初始定時時間
}

 
struct timeval {
    time_t      tv_sec;         // 秒
    suseconds_t tv_usec;        // 微妙 
};

itimeval由兩個timeval結構體組成,timeval包含tv_sec和tv_usec兩部分,其中tv_sec爲秒,tv_usec爲微秒(即1/1000000秒)
其中的new_value參數用來對計時器進行設置,it_interval爲計時間隔,it_value爲延時時長,下面例子中表示的是在setitimer方法調用成功後,延時1微秒便觸發一次SIGALRM信號,以後每隔200毫秒觸發一次SIGALRM信號。

settimer工作機制是,先對it_value倒計時,當it_value爲零時觸發信號,然後重置爲it_interval,繼續對it_value倒計時,一直這樣循環下去。

基於此機制,setitimer既可以用來延時執行,也可定時執行。

假如it_value爲0是不會觸發信號的,所以要能觸發信號,it_value得大於0;如果it_interval爲零,只會延時,不會定時(也就是說只會觸發一次信號)。

old_value參數,通常用不上,設置爲NULL,它是用來存儲上一次setitimer調用時設置的new_value值。

示例1 :

#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>

int count = 0;
void set_timer()
{
    struct itimerval itv;
    memset(&itv,0,sizeof(itv));
    itv.it_interval.tv_sec = 1;//每隔1秒
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec = 3;//第一次3秒
    itv.it_value.tv_usec = 0;

    int ret = setitimer(ITIMER_REAL, &itv, NULL);
    if(ret)
    {
        printf("setitimer failed!/n");
    }
}
void sigalrm_handler(int sig)
{
    if(sig == SIGALRM)
    {
        count++;
        printf("caught signal.. %d\n", count);
    }
    else
    {
        printf("caught signal failed!\n");	
    }	
}
int main()
{
    signal(SIGALRM, sigalrm_handler);
    set_timer();
    while (count < 5)
    {}
    exit(0);
}

輸出結果:

示例2: 阻塞的例子

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
int main(int argc, char *argv[])
{
    sigset_t block;
    struct itimerval itv;

    sigemptyset(&block);
    sigaddset(&block, SIGALRM);
    sigprocmask(SIG_BLOCK, &block, NULL);

    itv.it_interval.tv_sec = 2;
    itv.it_interval.tv_usec = 0;
    itv.it_value = itv.it_interval;
    setitimer(ITIMER_REAL, &itv, NULL);

    while (1) 
    {
        printf("%ld\n", time(NULL));
        printf("see\n");
        sigwaitinfo(&block, NULL);
    }
    return 0;
}

輸出結果:

 

參考鏈接:

定時器函數SetTime與setitimer

linux c stitimer 用法說明

Linux下的定時器以及POSIX定時器:timer_settime()

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章