Linux下的定時器有兩種,以下分別介紹:
1、alarm
如果不要求很精確的話,用alarm()和signal()就夠了
unsigned int alarm(unsigned int seconds)
函數說明: alarm()用來設置信號SIGALRM在經過參數seconds指定的秒數后傳送給目前的進程。如果參數seconds為0,則之前設置的鬧鐘會被取消,并將剩下的時間返回。
返回值: 返回之前鬧鐘的剩余秒數,如果之前未設鬧鐘則返回0。
alarm()執行后,進程將繼續執行,在后期(alarm以后)的執行過程中將會在seconds秒后收到信號SIGALRM并執行其處理函數。
#include
#include
#include
void sigalrm_fn(int sig)
{
printf("alarm!\n");
alarm(2);
return;
}
int main(void)
{
signal(SIGALRM, sigalrm_fn);
alarm(1);
while(1) pause();
}
|
2、setitimer()
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
setitimer()比alarm功能強大,支持3種類型的定時器:
ITIMER_REAL : 以系統真實的時間來計算,它送出SIGALRM信號。
ITIMER_VIRTUAL : -以該進程在用戶態下花費的時間來計算,它送出SIGVTALRM信號。
ITIMER_PROF : 以該進程在用戶態下和內核態下所費的時間來計算,它送出SIGPROF信號。
setitimer()第一個參數which指定定時器類型(上面三種之一);第二個參數是結構itimerval的一個實例;第三個參數可不做處理。
setitimer()調用成功返回0,否則返回-1。
下面是關于setitimer調用的一個簡單示范,在該例子中,每隔一秒發出一個SIGALRM,每隔0.5秒發出一個SIGVTALRM信號:
#include
#include
#include
#include
#include
#include
int sec;
void sigroutine(int signo){
switch (signo){
case SIGALRM:
printf("Catch a signal -- SIGALRM \n");
signal(SIGALRM, sigroutine);
break;
case SIGVTALRM:
printf("Catch a signal -- SIGVTALRM \n");
signal(SIGVTALRM, sigroutine);
break;
}
return;
}
int main()
{
struct itimerval value, ovalue, value2; //(1)
sec = 5;
printf("process id is %d\n", getpid());
signal(SIGALRM, sigroutine);
signal(SIGVTALRM, sigroutine);
value.it_value.tv_sec = 1;
value.it_value.tv_usec = 0;
value.it_interval.tv_sec = 1;
value.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &value, &ovalue); //(2)
value2.it_value.tv_sec = 0;
value2.it_value.tv_usec = 500000;
value2.it_interval.tv_sec = 0;
value2.it_interval.tv_usec = 500000;
setitimer(ITIMER_VIRTUAL, &value2, &ovalue);
for(;;)
;
}
|
(1) struct itimerval
struct itimerval {
struct timeval it_interval; /* timer interval */
struct timeval it_value; /* current value */
};
itimerval: i --> interval
val --> value
|
itimerval結構中的it_value是減少的時間,當這個值為0的時候就發出相應的信號了. 然后再將it_value設置為it_interval值.
(2) setitimer()
setitimer()為其所在進程設置一個定時器,如果itimerval.it_interval不為0(it_interval的兩個域都不為0),則該定時器將持續有效(每隔一段時間就會發送一個信號)
注意:Linux信號機制基本上是從Unix系統中繼承過來的。早期Unix系統中 的信號機制比較簡單和原始,后來在實踐中暴露出一些問題,因此,把那些建立在早期機制上的信號叫做"不可靠信號",信號值小于 SIGRTMIN(SIGRTMIN=32,SIGRTMAX=63)的信號都是不可靠信號。這就是"不可靠信號"的來源。它的主要問題是:進程每次處理 信號后,就將對信號的響應設置為默認動作。在某些情況下,將導致對信號的錯誤處理;因此,用戶如果不希望這樣的操作,那么就要在信號處理函數結尾再一次調 用signal(),重新安裝該信號。
http://tech.ccidnet.com/art/302/20071226/1322683_1.html
-------------------------------
信號是unix中所使用的進程通信的一種最古老的方法.系統使用它來同志一個或多個進程異步事件的發生.
linux系統庫bits/signum.h對信號名作了定義:
linux的大多數信號是提供給內核的,僅有少數幾種信號可以在信號間發送.
.SIGHUP 當終止一個終端時,內核就把這種信號發送給該終端所控制的所有進程.
.SIGINT 當一個用戶按下中斷鍵(ctrl+c)后,內核就向該終端用關聯的所有進程發送這個信號.
.SIGQUIT 當用戶按下(ctrl+),內核就向該終端用關聯的所有進程發送這個信號.
.SIGILL 當一個進程企圖執行一條非法指令時,內核就發送這個信號.
.SIGFPE 當產生浮點錯誤時,內核就發送這個信號.
.SIGKILL 這是一個非常特殊的信號,他可以從一個進程發送到另一個進程,使接收到該信號的進程終止.內核偶然也發送這種信號.
.SIGALRM 當一個定時器到時的時候,內核就發送這個信號.
.SIGSTOP 子進程結束信號.UNIX用它來實現系統調用exit(),wait();
信號的處理
unix的系統調用signal()用于接受一個指定的信號,并可以指定相應的處理方法.
在linux系統庫signal.h中,它的說明如下:
signal(int sig,sighandler_t handler);
sig用于指定信號類型.handle是用于處理該信號的函數.
handle還可以是:
.SIG_IGN 忽略這個信號.
.SIG_DFL 恢復對這個信號的默認處理.
例如:
main(){
signal(SIGINT,SIG_IGN);
printf(”hello!n”);
sleep(10);
printf(”hellon”);
}
上面的代碼忽略了SININT信號.
又例如:
int catch(int sig);
main(){
signal(SIGINT,catch);
printf(”hello!n”);
sleep(10);
printf(”hello!n”);
}
int catch(int sig){
printf(”catch signaln”);
return 1;
}
當用戶按下ctrl+c時,進程被中斷,catch()被執行.中斷處理函數處理完畢后,轉回斷點執行下面的指令.
當編寫自己的中斷處理函數時,注意下面兩點:
1.信號不能打斷系統調用.
2.信號不能打斷信號處理函數.
alarm(設置信號傳送鬧鐘)
定義函數
unsigned int alarm(unsigned int seconds);
函數說明
alarm()用來設置信號SIGALRM在經過參數seconds指定的秒數后傳送給目前的進程。如果參數seconds 為0,則之前設置的鬧鐘會被取消,并將剩下的時間返回。
返回值
返回之前鬧鐘的剩余秒數,如果之前未設鬧鐘則返回0。
范例
void handler() {
printf("hellon");
}
main()
{
int i;
signal(SIGALRM,handler);
alarm(5);
for(i=1;i<7;i++){
printf("sleep %d ...n",i);
sleep(1);
}
}
執行
sleep 1 ...
sleep 2 ...
sleep 3 ...
sleep 4 ...
sleep 5 ...
hello
sleep 6 ...
http://blog.csdn.net/sambian/archive/2006/04/30/698718.aspx