c實(shí)現(xiàn)的幾種定時(shí)器

原文:https://www.cnblogs.com/BKjungle/p/6127807.html


1.linux下調(diào)用系統(tǒng)函數(shù)alarm(),setitimer(),sleep(),usleep()(實(shí)現(xiàn)微妙定時(shí)),

2.單純c語(yǔ)言實(shí)現(xiàn)gettimeofday()(微妙定時(shí)),time(),

3.windows可用Sleep()實(shí)現(xiàn)微秒級(jí)定時(shí)

4 IO復(fù)用的 ?select 函數(shù) 實(shí)現(xiàn)

1.alarm()

#include?

unsigned?int?alarm(unsigned?int?seconds);

函數(shù)返回值

成功:如果調(diào)用此alarm()前,進(jìn)程已經(jīng)設(shè)置了鬧鐘時(shí)間,則返回上一個(gè)鬧鐘時(shí)間的剩余時(shí)間,否則返回0。不阻塞?。?!

出錯(cuò):-1

作用: ?調(diào)用?alarm?函數(shù)即設(shè)定一個(gè)鬧鐘,也就是告訴內(nèi)核在?seconds?秒之后給當(dāng)前進(jìn)程發(fā)?SIGALRM?信號(hào),默認(rèn)處理動(dòng)作是終止當(dāng)前進(jìn)程。鬧鐘返

回值是?0?或者是以前設(shè)定的鬧鐘時(shí)間還余下的秒數(shù)。如果?seconds?值為?0,表示取消以前設(shè)定的鬧鐘,函數(shù)的返回值仍然

是以前設(shè)定的鬧鐘時(shí)間還余下的秒數(shù)。

------ alarm

#include?

#include?

int?main(void)

{

int?counter;

alarm(1);

for(counter=0;?1;?counter++)

printf("counter=%d?",?counter);

return?0;

}

這個(gè)程序的作用是?1?秒鐘之內(nèi)不停地?cái)?shù)數(shù),1?秒鐘到了就被?SIGALRM?信號(hào)終

止。


-----------》》1.1 配合pause函數(shù)實(shí)現(xiàn)sleep函數(shù)!

#include?

int?pause(void);

pause?函數(shù)使調(diào)用進(jìn)程掛起直到有信號(hào)遞達(dá)。如果信號(hào)的處理動(dòng)作是終止進(jìn)程,則進(jìn)程終止,pause?函數(shù)沒有機(jī)會(huì)返回;如果信號(hào)的處理動(dòng)作是忽略,則

進(jìn)程繼續(xù)處于掛起狀態(tài),pause?不返回;如果信號(hào)的處理動(dòng)作是捕捉,則調(diào)用了信號(hào)處理函數(shù)之后?pause?返回-1,errno?設(shè)置為?EINTR,所以?pause?只有出錯(cuò)

的返回值(想想以前還學(xué)過(guò)什么函數(shù)只有出錯(cuò)返回值?)。錯(cuò)誤碼?EINTR?表示“被信號(hào)中斷”。

下面我們用?alarm?和?pause?實(shí)現(xiàn)?sleep(3)函數(shù),稱為?mysleep。

mysleep

#include?

#include?

#include?

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?函數(shù)調(diào)用?mysleep?函數(shù),后者調(diào)用?sigaction?注冊(cè)了?SIGALRM?信號(hào)? ? ? ? 的處理函數(shù)?sig_alrm。

2.?調(diào)用?alarm(nsecs)設(shè)定鬧鐘。

3.?調(diào)用?pause?等待,內(nèi)核切換到別的進(jìn)程運(yùn)行。

4.?nsecs?秒之后,鬧鐘超時(shí),內(nèi)核發(fā)?SIGALRM?給這個(gè)進(jìn)程。

5.?從內(nèi)核態(tài)返回這個(gè)進(jìn)程的用戶態(tài)之前處理未決信號(hào),發(fā)現(xiàn)有?SIGALRM?信號(hào),其處理函數(shù)是?sig_alrm。

6.?切換到用戶態(tài)執(zhí)行?sig_alrm?函數(shù),進(jìn)入?sig_alrm?函數(shù)時(shí)?SIGALRM?信號(hào)被自動(dòng)屏蔽,從?sig_alrm?函數(shù)返回時(shí)?SIGALRM?信號(hào)自動(dòng)解除屏蔽。然后

自動(dòng)執(zhí)行系統(tǒng)調(diào)用?sigreturn?再次進(jìn)入內(nèi)核,再返回用戶態(tài)繼續(xù)執(zhí)行進(jìn)程的主控制流程(main?函數(shù)調(diào)用的?mysleep?函數(shù))。

7.?pause?函數(shù)返回-1,然后調(diào)用?alarm(0)取消鬧鐘,調(diào)用?sigaction?恢復(fù)SIGALRM?信號(hào)以前的處理動(dòng)作。




2.setitimer()-----------------------?

常用到的函數(shù):

#include?

int?getitimer?(int?which,?struct?itimerval*?value);

int?setitimer?(int?which,?struct?itimerval*?newvalue,?struct?itimerval*?oldvalue);

which有三種狀態(tài):

ITIMER_REAL: 對(duì)指定時(shí)間值,按自然時(shí)間計(jì)數(shù), 時(shí)間到發(fā)出SIGALRM信號(hào).

ITIMER_VIRTUAL:?對(duì)指定時(shí)間值,?當(dāng)只在用戶態(tài)時(shí)(進(jìn)程執(zhí)行的時(shí)候)計(jì)數(shù), ?時(shí)間到發(fā)出SIGVTALRM信號(hào).

ITIMER_PROF: 對(duì)指定時(shí)間值, 用戶態(tài)或內(nèi)核態(tài)(進(jìn)程執(zhí)行與系統(tǒng)為進(jìn)程調(diào)度)都計(jì)數(shù),?時(shí)間到,?發(fā)出SIGPROF信號(hào), 與ITIMER_VIRTVAL聯(lián)合,?常用來(lái)計(jì)算系統(tǒng)內(nèi)核時(shí)間和用戶時(shí)間.

struct?timeval

{

long?tv_sec;/*?秒?*/

long?tv_usec;/*?微秒?*/

};

struct?itimerval

{

struct?timeval?it_interval;?/*?時(shí)間間隔?*///循環(huán)定時(shí)時(shí)間

struct?timeval?it_value;/*?當(dāng)前時(shí)間計(jì)數(shù)?*/第一次計(jì)時(shí)時(shí)間

};

it_interval用來(lái)指定每隔多長(zhǎng)時(shí)間執(zhí)行任務(wù),?it_value用來(lái)保存當(dāng)前時(shí)間離執(zhí)行任務(wù)還有多長(zhǎng)時(shí)間.?比如說(shuō),?你指定it_interval為2秒(微秒為0),?開始的時(shí)候我們把it_value的時(shí)間也設(shè)定為2秒(微秒為0),?當(dāng)過(guò)了一秒,?it_value就減少一個(gè)為1,?再過(guò)1秒,?則it_value又減少1,?變?yōu)?,?這個(gè)時(shí)候發(fā)出信號(hào)(告訴用戶時(shí)間到了,?可以執(zhí)行任務(wù)了),?并且系統(tǒng)自動(dòng)把it_value的置重置為it_interval的值,?即2秒,?再重新計(jì)數(shù).


?-------------------------------代碼實(shí)現(xiàn)

#include

#include

#include

#include

#include

#include

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定時(shí)器,每隔2秒鐘都會(huì)發(fā)送一個(gè)SIGALRM信號(hào),當(dāng)主函數(shù)接收到了這個(gè)信號(hào)之后,調(diào)用信號(hào)處理函數(shù)prompt_info在標(biāo)準(zhǔn)錯(cuò)誤上輸出time?is?running?out這個(gè)字符串。

對(duì)于ITIMER_VIRTUAL和ITIMER_PROF的使用方法類似,當(dāng)你在setitimer里面設(shè)置的定時(shí)器為ITIMER_VIRTUAL的時(shí)候,你把sigaction里面的SIGALRM改為SIGVTALARM,?同理,ITIMER_PROF對(duì)應(yīng)SIGPROF。

不過(guò),你可能會(huì)注意到,當(dāng)你用ITIMER_VIRTUAL和ITIMER_PROF的時(shí)候,你拿一個(gè)秒表,你會(huì)發(fā)現(xiàn)程序輸出字符串的時(shí)間間隔會(huì)不止2秒,甚至5-6秒才會(huì)輸出一個(gè),那是因?yàn)閏pu在用戶與內(nèi)核切換之間也會(huì)浪費(fèi)時(shí)間,這段時(shí)間是不計(jì)入在指定時(shí)間范圍之內(nèi)的。


3.time()或gettimeofday()利用時(shí)間差來(lái)計(jì)算--------------------------------------------------------------------------------------------------------------------------


1.?#include?

2.?#include?

3.?#include?

4.?#include?

5.?#include? //包含time()函數(shù)

6.#include <sys/time.h>//包含gettimeofday()函數(shù)

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.?????????/*獲取當(dāng)前時(shí)間*/

30.?????????time(&nowtime);

31.?????????/*和上一次的時(shí)間做比較,如果大于等于2秒,則立刻發(fā)送信號(hào)*/

32.?????????if(nowtime?-?lasttime?>=?2)

33.?????????{

34.?????????????/*向主進(jìn)程發(fā)送信號(hào),實(shí)際上是自己給自己發(fā)信號(hào)*/

35.?????????????sigqueue(getpid(),?50,?tsval);

36.?????????????lasttime?=?nowtime;

37.?????????}

38.?????}

39.?????return0;

40.?}


如果你想更精確的計(jì)算時(shí)間差,你可以把?time?函數(shù)換成gettimeofday,這個(gè)可以精確到微妙。

上面介紹的幾種定時(shí)方法各有千秋,在計(jì)時(shí)效率上、方法上和時(shí)間的精確度上也各有不同,采用哪種方法,就看你程序的需要


4 sleep實(shí)現(xiàn)方法--------------------?

下面我們來(lái)看看用sleep以及usleep怎么實(shí)現(xiàn)定時(shí)執(zhí)行任務(wù)。

下載:?timer2.c

1.?#include?

2.?#include?

3.?#include?

4.?#include?

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.?????????/*向主進(jìn)程發(fā)送信號(hào),實(shí)際上是自己給自己發(fā)信號(hào)*/

27.?????????sigqueue(getpid(),?50,?tsval);

28.?????}

29.?????return0;

30.?}

看到了吧,這個(gè)要比上面的簡(jiǎn)單多了,而且你用秒表測(cè)一下,時(shí)間很準(zhǔn),指定2秒到了就給你輸出一個(gè)字符串。所以,如果你只做一般的定時(shí),到了時(shí)間去執(zhí)行一個(gè)任務(wù),這種方法是最簡(jiǎn)單的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 信號(hào)的基本概念 信號(hào)被認(rèn)為是一種軟件中斷(區(qū)別于硬件中斷),信號(hào)機(jī)制提供了一種在單進(jìn)程/線程下處理異步事件的方法。...
    小葉大孟閱讀 2,356評(píng)論 0 1
  • 一、Linux系統(tǒng)概述 不加引號(hào)可理解為宏,直接替換,單引號(hào)中特殊字符會(huì)被解釋為普通字符,雙引號(hào)中$,,'還是特殊...
    赤果_b4a7閱讀 1,632評(píng)論 0 2
  • 一、信號(hào)及信號(hào)來(lái)源 信號(hào)本質(zhì) 信號(hào)是在軟件層次上對(duì)中斷機(jī)制的一種模擬,在原理上,一個(gè)進(jìn)程收到一個(gè)信號(hào)與處理器收到一...
    丶Em1tu0F閱讀 1,506評(píng)論 0 1
  • 信號(hào)信號(hào)是linux操作系統(tǒng)進(jìn)程間通信的一種方式,一個(gè)應(yīng)用進(jìn)程可以接受、發(fā)送信號(hào)給另一個(gè)進(jìn)程,當(dāng)進(jìn)程捕獲到某個(gè)信號(hào)...
    zhile_doing閱讀 588評(píng)論 0 0
  • 作業(yè)1:輸出一個(gè)數(shù)最后一位 作業(yè)2:輸出最大值 作業(yè)3 輸出季節(jié)
    GXMCRH閱讀 390評(píng)論 0 0

友情鏈接更多精彩內(nèi)容