linux用戶態定時器的使用---19


原創博文,轉載請標明出處--周學偉http://www.cnblogs.com/zxouxuewei/

linux操作系統為每一個進程提供了3個內部計時器。

ITIMER_REAL;ITIMER_VIRTUAL;ITIMER_PROF.

 

ITIMER_REAL:給定一個指定的時間間隔,按照實際的時間來減少這個計數,當時間間隔為0的時候發出SIGALRM信號。

ITIMER_VIRTUAL:給定一個時間間隔,當進程執行的時候才減少計數,時間間隔為0的時候發出SIGVTALRM信號。

ITIMER_PROF:給定一個時間間隔,當進程執行或者是系統為進程調度的時候,減少計數,時間到了,發出SIGPROF信號,這個和TIMER_VIRTUAL聯合,常用來計算系統內核時間和用戶時間。

 

看一下getitimer的數據手冊

getitimer, setitimer - get or set value of an interval timer

 

#include <sys/time.h>

int getitimer(int which, struct itimerval *value);

int setitimer(int which, char struct itimerval *value, struct itimerval *ovalue);

 

ITIMER_REAL;ITIMER_VIRTUAL;ITIMER_PROF.就是三個定時器,在使用的時候,當其中的任何一個時間到了,都會給進程發送一個信號,然后定時器重新被裝填,重新開始定時動作。

 

它們對應的信號

ITIMER_REAL    ---- SIGALRM

ITIMER_VIRTUAL ---- SIGVTALRM

ITIMER_PROF    ---- SIGPROF

 

函數中的which就是選擇這三個定時器中的一個。

 

下面是描述時間結構體value的

struct itimerval {

    struct timeval it_interval; //下一個值

    struct timeval it_value;    //當前的值

};

struct timeval {

    long tv_sec;  //秒

    long tv_usec; //毫秒

};

一個表示時間的結構體,一個含有時間結構體的結構體。

 

使用定時器的時候,首先定義一個時間結構體,然后初始化這個時間結構體的秒和毫秒。然后使用setitimer函數,第一個參數指定使用哪一個定時器,第二個參數就是傳遞進去的時間結構體,第三個參數為NULL。這樣就設定好了一個定時器了。它就可以開始工作了。

 

說一下返回值: 函數調用成功返回0, 錯誤返回-1,並且設置出錯值errno。

當出錯的時候:可能是value或者是ovalue指針無效;或者是定時器搞錯了,不是這三個中的一個;或者是時間結構體中的毫秒超出了0到999999的范圍。

 

由於當定時器的時間到了的時候會引發一個信號,因此我們必須對信號進行處理,因此需要了解一下信號處理的函數。

我們可以修改linux系統信號的相關聯的動作,也就是當捕獲到某個信號時需要執行什么函數。有點像是可以更改函數指針指向的函數一樣。

有這么一個函數可以完成這個問題:sigaction。

也就是sig-action,signal-action,信號動作。

#include<sginal.h>

int sigaction(int signo, const struct sigacton *rstrict act, struct sigaction *restrict oact);

這個函數具有三個參數,第一個是信號的名字,直接寫系統的信號名,比如SIGALRM之類的。第二個參數是一個結構體,表述了信號相關的東西,我們 修改的函數指針就在里面。第三個函數是用來返回的,返回該信號的上一個動作,也就是上一個這個信號結構體里面的函數指針指向的函數。

 

下面看一下這個信號結構體。

struct sigaction {

    void (*sa_handler)(int);

    sigset_t sa_mask;

    int sa_flags;

 

    void (*sa_sigaction)(int, siginfo_t *, void *);

};

在使用的時候,sa_handler和sa_sigaction只是用一個。

sa_mask是和sa_handler一起的。

sa_mask表示了一個信號集合,在調用sigaction之前要先用sigemptyset把sa_mask加入到進程的信號屏蔽字當中。

sigemptyset函數初始化一個sigset_t *類型的信號集合,清除里面的所有信號。

使用函數sigaction(SIGALRM, &tact, NULL)就是把SIGALRM的信號的觸發動作變成tact結構體中的sa_handler或者sa_sigaction所指向的函數了。

 

例子如下,每隔2秒鍾打印一行字。

一個函數用來設置信號相關的函數綁定,一個函數用來初始化定時器並且啟動它。

然后程序需要運行很久,放到死循環里面去,才能看出來效果,一般的應用程序,都不會自動退出的,往往是永遠不退出,或者是等待用戶關閉它。

 

#include<sys/time.h>  
#include<stdio.h>  
#include<unistd.h>  
#include<signal.h>  
#include<string.h>  
static char msg[] = "time is running out./n";  
static int len;  
void prompt_info(int signo)  
{  
    write(STDERR_FILENO, msg, len);  
}  
void init_sigaction(void)  
{  
    struct sigaction tact;  
    tact.sa_handler = prompt_info;  
    tact.sa_flags = 0;  
    sigemptyset(&tact.sa_mask);  
    sigaction(SIGALRM, &tact, NULL);  
}  
void init_time()   
{  
    struct itimerval value;  
    value.it_value.tv_sec = 2;  
    value.it_value.tv_usec = 0;  
    value.it_interval = value.it_value;  
    setitimer(ITIMER_REAL, &value, NULL);  
}  
int main()  
{  
    len = strlen(msg);  
    init_sigaction();  
    init_time();  
    while(1);  
    exit(0);  
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM