Unix環境程式設計之定時、訊號與中斷

有價值炮灰發表於2015-04-08

在linux下實現精度較高的定時功能,需要用到setitimer 和 getitimer函式。

 

函式原型:

 

#include <sys/time.h>
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value,
                     struct itimerval *old_value);

 

· 函式getitimer()把指定的定時器型別( ITIMER_REAL,  ITIMER_VIRTUAL,  或 ITIMER_PROF中的一個)寫入curr_value指向的結構。

it_value設定為定時器剩餘時間(若定時器關閉則為0)。類似的,it_interval設定為復位時間。

 

分析形參:

1. int which

  which為定時器型別,setitimer支援3種型別的定時器:
ITIMER_REAL: 以系統真實的時間來計算,它送出SIGALRM訊號。
ITIMER_VIRTUAL: -以該程式在使用者態下花費的時間來計算,它送出SIGVTALRM訊號。
ITIMER_PROF: 以該程式在使用者態下和核心態下所費的時間來計算,它送出SIGPROF訊號。
 
2. const struct itimerval *value
  value 是一個指向itimerval型別的指標,介紹如下
 
struct itimerval 
{
    struct timeval it_interval;//next value
    struct timeval it_value;//current value
};

timeval也是一個資料型別:

struct timeval 
{
    long tv_sec;
    long tv_usec;
};

  it_interval指定間隔時間,it_value指定初始定時時間。如果只指定it_value,就是實現一次定時;如果同時指定 it_interval,則超時後,系統會重新初始化it_value為it_interval,實現重複定時;兩者都清零,則會清除定時器。tv_sec提供秒級精度,tv_usec提供微秒級精度,以值大的為先。

3. struct itimerval *ovalue

  ovalue用來儲存先前的值,通常設定為NULL。

 

每次定時迴圈結束會產生中斷,通常會用到signal函式捕捉處理,原型為:

#include<signal.h>
void  (* signal(int sig, void (*func) (int)) ) (int);

   signal()是一個系統呼叫,常用來設定某個訊號(sig)的處理方法(func):

訊號型別(sig)

(1) 與程式終止相關的訊號。當程式退出,或者子程式終止時,發出這類訊號。

(2) 與程式例外事件相關的訊號。如程式越界,或企圖寫一個只讀的記憶體區域(如程式正文區),或執行一個特權指令及其他各種硬體錯誤。

(3) 與在系統呼叫期間遇到不可恢復條件相關的訊號。如執行系統呼叫exec時,原有資源已經釋放,而目前系統資源又已經耗盡。

(4) 與執行系統呼叫時遇到非預測錯誤條件相關的訊號。如執行一個並不存在的系統呼叫。

(5) 在使用者態下的程式發出的訊號。如程式呼叫系統呼叫kill向其他程式傳送訊號。

(6) 與終端互動相關的訊號。如使用者關閉一個終端,或按下break鍵等情況。

(7) 跟蹤程式執行的訊號。

下列巨集常量表示式指定了標準的訊號值:

Marcro Signal
SIGABRT 異常終止,如呼叫abort().
SIGFPE 如除0或操作結果溢位(不一定是浮點操作).
SIGILL 非法指令或無效的函式映象,通常由於程式碼錯誤或執行資料引起.
SIGINT 互動式中斷訊號,通常由使用者產生.
SIGSEGV 段衝突.訪問非法儲存空間時產生.
SIGTERM 發給本程式的中止訊號.

 

 
 
 
 
 
 
 
 
 
 
 
 
處理方法(func)有三種,分別是:
  預設處理(SIG_DFL), 訊號以其預設指定的行為進行處理。
  忽略訊號(SIG_IGN), 訊號被忽略而且程式會繼續往下執行,即使沒有任何意義。
  函式處理,以使用者指定的函式來處理訊號。
 
僅看原型比較抽象,舉個例子就知道了:
   
#include<stdio.h>
#include<sys/time.h>
#include<signal.h>


void response(void);
int main()
{
    struct itimerval my_timer;
    long n_sec, n_usec;
    my_timer.it_interval.tv_sec = 0;
    my_timer.it_interval.tv_usec = 300*1000;//300ms
    my_timer.it_value.tv_sec = 2;   //2s
    my_timer.it_value.tv_usec = 0;

    setitimer(ITIMER_REAL, &my_timer, NULL);
    
    signal(SIGALRM,(__sighandler_t)&response);
    while(1)
        ;
    return 0;
}

void response(void)
{
    printf("Receive signal!!\n");
}

上述程式碼片段將定時器初始值設為2s,迴圈值為300ms,則當setitimer函式執行以後2s產生SIGALRM中斷,由signal函式指定中斷處理函式為response();

2s之後,每隔300ms產生一次SIGALRM中斷。

 

參考文章:
http://www.uml.org.cn/c%2B%2B/200812083.asp
 

 

相關文章