原文: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)單的。