linux應用層定時器的常用方法
一、alarm
如果不要求很精確的話,用 alarm() 和 signal() 就夠了。
unsigned int alarm(unsigned int seconds)
專門為SIGALRM訊號而設,在指定的時間seconds秒後,將向程序本身傳送SIGALRM訊號,又稱為鬧鐘時間。程序呼叫alarm後,任何以前的alarm()呼叫都將無效。如果引數seconds為零,那麼程序內將不再包含任何鬧鐘時間。如果呼叫alarm()前,程序中已經設定了鬧鐘時間,則返回上一個鬧鐘時間的剩餘時間,否則返回0。
示例:
#include <stdio.h> #include <unistd.h> #include<signal.h> void sigalrm_fn(int sig) { printf("alarm!\n"); alarm(2); return; } int main(void) { signal(SIGALRM, sigalrm_fn); alarm(2); while(1) pause(); }
二、setitimer
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue)); int getitimer(intwhich, struct itimerval *value); strcut timeval { long tv_sec; /*秒*/ long tv_usec; /*微秒*/ }; struct itimerval { struct timeval it_interval; /*時間間隔*/ struct timeval it_value; /*當前時間計數*/ };
setitimer() 比 alarm() 功能強大,支援3種類型的定時器:
①ITIMER_REAL:給一個指定的時間間隔,按照實際的時間來減少這個計數,當時間間隔為0的時候發出SIGALRM訊號。
②ITIMER_VIRTUAL:給定一個時間間隔,當程序執行的時候才減少計數,時間間隔為0的時候發出SIGVTALRM訊號。
③ITIMER_PROF:給定一個時間間隔,當程序執行或者是系統為程序排程的時候,減少計數,時間到了,發出SIGPROF訊號。
setitimer() 第一個引數 which 指定定時器型別(上面三種之一);第二個引數是結構 itimerval 的一個例項;第三個引數可不做處理。
例子:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <time.h> #include <sys/time.h> 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; printf("process id is %d ", 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); 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(;;); }
三、用 sleep 以及 usleep 實現定時執行任務
#include <signal.h> #include <unistd.h> #include <string.h> #include <stdio.h> static char msg[] = "I received a msg.\n"; int len; void show_msg(int signo) { write(STDERR_FILENO, msg, len); } int main() { struct sigaction act; union sigval tsval; act.sa_handler = show_msg; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(50, &act, NULL); len = strlen(msg); while ( 1 ) { sleep(2); /*睡眠2秒*/ /*向主程序傳送訊號,實際上是自己給自己發訊號*/ sigqueue(getpid(), 50, tsval); } return 0; }
如果你只做一般的定時,到了時間去執行一個任務,這種方法是最簡單的。
四、使用 select 來提供精確定時和休眠
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
n 指監視的檔案描述符範圍,通常設為所要select的fd+1;readfds,writefds 和 exceptfds分別是讀,寫和異常檔案描述符集;timeout 為超時時間。
示例:
int msSleep(long ms) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = ms; return select(0, NULL, NULL, NULL, &tv); }
setitimer 和 select 都能實現程序的精確休眠,這裡給出了一個簡單的基於 select 的實現。我不推薦使用 setitimer,因為 Linux 系統提供的 timer 有限(每個程序至多能設3個不同型別的 timer),而且 setitimer 實現起來沒有 select 簡單。
本文轉載自:https://blog.csdn.net/lu_embedded/article/details/53080496