1.linux下調用系統函數alarm(),setitimer(),sleep(),usleep()(實現微妙定時),linux
2.單純c語言實現gettimeofday()(微妙定時),time(),windows
3.windows可用Sleep()實現微秒級定時函數
1.alarm()進程
#include <unistd.h>
unsigned int alarm(unsigned int seconds);字符串
函數返回值get
成功:若是調用此alarm()前,進程已經設置了鬧鐘時間,則返回上一個鬧鐘時間的剩餘時間,不然返回0。不阻塞!!!string
出錯:-1it
做用: 調用 alarm 函數即設定一個鬧鐘,也就是告訴內核在 seconds 秒以後給當前進程發 SIGALRM 信號,默認處理動做是終止當前進程。鬧鐘返io
回值是 0 或者是之前設定的鬧鐘時間還餘下的秒數。若是 seconds 值爲 0,表示取消之前設定的鬧鐘,函數的返回值仍然
是之前設定的鬧鐘時間還餘下的秒數。
例ast
------ alarm
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int counter;
alarm(1);
for(counter=0; 1; counter++)
printf("counter=%d ", counter);
return 0;
}
這個程序的做用是 1 秒鐘以內不停地數數,1 秒鐘到了就被 SIGALRM 信號終
止。
-----------》》1.1 配合pause函數實現sleep函數!
#include <unistd.h>
int pause(void);
pause 函數使調用進程掛起直到有信號遞達。若是信號的處理動做是終止進程,則進程終止,pause 函數沒有機會返回;若是信號的處理動做是忽略,則
進程繼續處於掛起狀態,pause 不返回;若是信號的處理動做是捕捉,則調用了信號處理函數以後 pause 返回-1,errno 設置爲 EINTR,因此 pause 只有出錯
的返回值(想一想之前還學過什麼函數只有出錯返回值?)。錯誤碼 EINTR 表示「被信號中斷」。
下面咱們用 alarm 和 pause 實現 sleep(3)函數,稱爲 mysleep。
mysleep
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void sig_alrm(int signo)
{
/* nothing to do */
}
unsigned int mysleep(unsigned int nsecs)
{
struct sigaction newact, oldact;
unsigned int unslept;
newact.sa_handler = sig_alrm;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGALRM, &newact, &oldact);
alarm(nsecs);
pause();
unslept = alarm(0);
sigaction(SIGALRM, &oldact, NULL);
return unslept;
}
int main(void)
{
while(1){
mysleep(2);
printf("Two seconds passed\n");
}
return 0;
}
1. main 函數調用 mysleep 函數,後者調用 sigaction 註冊了 SIGALRM 信號 的處理函數 sig_alrm。
2. 調用 alarm(nsecs)設定鬧鐘。
3. 調用 pause 等待,內核切換到別的進程運行。
4. nsecs 秒以後,鬧鐘超時,內核發 SIGALRM 給這個進程。
5. 從內核態返回這個進程的用戶態以前處理未決信號,發現有 SIGALRM 信號,其處理函數是 sig_alrm。
6. 切換到用戶態執行 sig_alrm 函數,進入 sig_alrm 函數時 SIGALRM 信號被自動屏蔽,從 sig_alrm 函數返回時 SIGALRM 信號自動解除屏蔽。而後
自動執行系統調用 sigreturn 再次進入內核,再返回用戶態繼續執行進程的主控制流程(main 函數調用的 mysleep 函數)。
7. pause 函數返回-1,而後調用 alarm(0)取消鬧鐘,調用 sigaction 恢復SIGALRM 信號之前的處理動做。
2.setitimer()----------------------------------------------------------------------------------------------------------------------------------------------------------------------
經常使用到的函數:
#include <sys/time.h>
int getitimer (int which, struct itimerval* value);
int setitimer (int which, struct itimerval* newvalue, struct itimerval* oldvalue);
which有三種狀態:
ITIMER_REAL: 對指定時間值,按天然時間計數, 時間到發出SIGALRM信號.
ITIMER_VIRTUAL: 對指定時間值, 當只在用戶態時(進程執行的時候)計數, 時間到發出SIGVTALRM信號.
ITIMER_PROF: 對指定時間值, 用戶態或內核態(進程執行與系統爲進程調度)都計數, 時間到, 發出SIGPROF信號, 與ITIMER_VIRTVAL聯合, 經常使用來計算系統內核時間和用戶時間.
struct timeval
{
long tv_sec; /* 秒 */
long tv_usec; /* 微秒 */
};
struct itimerval
{
struct timeval it_interval; /* 時間間隔 *///循環定時時間
struct timeval it_value; /* 當前時間計數 */第一次計時時間
};
it_interval用來指定每隔多長時間執行任務, it_value用來保存當前時間離執行任務還有多長時間. 好比說, 你指定it_interval爲2秒(微秒爲0), 開始的時候咱們把it_value的時間也設定爲2秒(微秒爲0), 當過了一秒, it_value就減小一個爲1, 再過1秒, 則it_value又減小1, 變爲0, 這個時候發出信號(告訴用戶時間到了, 能夠執行任務了), 而且系統自動把it_value的置重置爲it_interval的值, 即2秒, 再從新計數.
-------------------------------代碼實現
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
static char msg[] = "time is running out.\n";
static int len;
/* time's up */
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;
/* set ITIMER_REAL */
setitimer (ITIMER_REAL, &value, NULL);
}
int main (int argc, char** argv)
{
len = strlen (msg);
init_sigaction ();
init_time ();
while (1);
exit (0);
}
該程序的ITMER_REAL定時器,每隔2秒鐘都會發送一個SIGALRM信號,當主函數接收到了這個信號以後,調用信號處理函數prompt_info在標準錯誤上輸出time is running out這個字符串。
對於ITIMER_VIRTUAL和ITIMER_PROF的使用方法相似,當你在setitimer裏面設置的定時器爲ITIMER_VIRTUAL的時候,你把sigaction裏面的SIGALRM改成SIGVTALARM, 同理,ITIMER_PROF對應SIGPROF。
不過,你可能會注意到,當你用ITIMER_VIRTUAL和ITIMER_PROF的時候,你拿一個秒錶,你會發現程序輸出字符串的時間間隔會不止2秒,甚至5-6秒纔會輸出一個,那是由於cpu在用戶與內核切換之間也會浪費時間,這段時間是不計入在指定時間範圍以內的。
3.time()或gettimeofday()利用時間差來計算--------------------------------------------------------------------------------------------------------------------------
1. #include <signal.h>
2. #include <unistd.h>
3. #include <string.h>
4. #include <stdio.h>
5. #include <time.h> //包含time()函數
6.#include <sys/time.h>//包含gettimeofday()函數
7. staticchar msg[] = "I received a msg.\n";
8. int len;
9. static time_t lasttime;
10. void show_msg(int signo)
11. {
12. write(STDERR_FILENO, msg, len);
13. }
14. intmain()
15. {
16. structsigaction act;
17. unionsigval tsval;
18.
19. act.sa_handler = show_msg;
20. act.sa_flags = 0;
21. sigemptyset(&act.sa_mask);
22. sigaction(50, &act, NULL);
23.
24. len = strlen(msg);
25. time(&lasttime);
26. while( 1 )
27. {
28. time_tnowtime;
29. /*獲取當前時間*/
30. time(&nowtime);
31. /*和上一次的時間作比較,若是大於等於2秒,則馬上發送信號*/
32. if(nowtime - lasttime >= 2)
33. {
34. /*向主進程發送信號,其實是本身給本身發信號*/
35. sigqueue(getpid(), 50, tsval);
36. lasttime = nowtime;
37. }
38. }
39. return0;
40. }
若是你想更精確的計算時間差,你能夠把 time 函數換成gettimeofday,這個能夠精確到微妙。
上面介紹的幾種定時方法各有千秋,在計時效率上、方法上和時間的精確度上也各有不一樣,採用哪一種方法,就看你程序的須要
4 sleep實現方法-------------------------------------------------------------------------------------------------------------------------------------------------------------
下面咱們來看看用sleep以及usleep怎麼實現定時執行任務。下載: timer2.c1. #include <signal.h> 2. #include <unistd.h> 3. #include <string.h> 4. #include <stdio.h> 5. 6. staticchar msg[] = "I received a msg.\n"; 7. int len; 8. void show_msg(int signo) 9. { 10. write(STDERR_FILENO, msg, len); 11. } 12. intmain() 13. { 14. structsigaction act; 15. unionsigval tsval; 16. 17. act.sa_handler = show_msg; 18. act.sa_flags = 0; 19. sigemptyset(&act.sa_mask); 20. sigaction(50, &act, NULL); 21. 22. len = strlen(msg); 23. while( 1 ) 24. { 25. sleep(2); /*睡眠2秒*/ 26. /*向主進程發送信號,其實是本身給本身發信號*/ 27. sigqueue(getpid(), 50, tsval); 28. } 29. return0; 30. }看到了吧,這個要比上面的簡單多了,並且你用秒錶測一下,時間很準,指定2秒到了就給你輸出一個字符串。因此,若是你只作通常的定時,到了時間去執行一個任務,這種方法是最簡單的。