c實現的幾種定時器

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秒到了就給你輸出一個字符串。因此,若是你只作通常的定時,到了時間去執行一個任務,這種方法是最簡單的。

相關文章
相關標籤/搜索