POSIX定时器
?
創建一個定時器:
int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)??? 進程可以通過調用timer_create()創建特定的定時器,定時器是每個進程自己的,不是在fork時繼承的。clock_id說明定時器是基于哪個時鐘的,*timerid裝載的是被創建的定時器的ID。該函數創建了定時器,并將他的ID?放入timerid指向的位置中。參數evp指定了定時器到期要產生的異步通知。如果evp為NULL,那么定時器到期會產生默認的信號,對?CLOCK_REALTIMER來說,默認信號就是SIGALRM。如果要產生除默認信號之外的其它信號,程序必須將?evp->sigev_signo設置為期望的信號碼。struct?sigevent?結構中的成員evp->sigev_notify說明了定時器到期時應該采取的行動。通常,這個成員的值為SIGEV_SIGNAL,這個值說明在定時器到期時,會產生一個信號。程序可以將成員evp->sigev_notify設為SIGEV_NONE來防止定時器到期時產生信號。
?
??? 如果幾個定時器產生了同一個信號,處理程序可以用?evp->sigev_value來區分是哪個定時器產生了信號。要實現這種功能,程序必須在為信號安裝處理程序時,使用struct?sigaction的成員sa_flags中的標志符SA_SIGINFO。
?
clock_id取值為以下:
CLOCK_REALTIME?:Systemwide?realtime?clock.
CLOCK_MONOTONIC:Represents?monotonic?time.?Cannot?be?set.
CLOCK_PROCESS_CPUTIME_ID?:High?resolution?per-process?timer.
CLOCK_THREAD_CPUTIME_ID?:Thread-specific?timer.
CLOCK_REALTIME_HR?:High?resolution?version?of?CLOCK_REALTIME.
CLOCK_MONOTONIC_HR?:High?resolution?version?of?CLOCK_MONOTONIC.
?
struct?sigevent
{
int?sigev_notify;?//notification?type
int?sigev_signo;?//signal?number
union?sigval???sigev_value;?//signal?value
void?(*sigev_notify_function)(union?sigval);
pthread_attr_t?*sigev_notify_attributes;
}
union?sigval
{
int?sival_int;?//integer?value
void?*sival_ptr;?//pointer?value
}
通過將evp->sigev_notify設定為如下值來定制定時器到期后的行為:
SIGEV_NONE:什么都不做,只提供通過timer_gettime和timer_getoverrun查詢超時信息。
SIGEV_SIGNAL:?當定時器到期,內核會將sigev_signo所指定的信號傳送給進程。在信號處理程序中,si_value會被設定會sigev_value。
SIGEV_THREAD:?當定時器到期,內核會(在此進程內)以sigev_notification_attributes為線程屬性創建一個線程,并且讓它執行sigev_notify_function,傳入sigev_value作為為一個參數。
?
啟動一個定時器:
??? timer_create()所創建的定時器并未啟動。要將它關聯到一個到期時間以及啟動時鐘周期,可以使用timer_settime()。
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspect *ovalue);
?
struct itimespec{
??? struct timespec it_interval;?
??? struct timespec it_value;???
};?
??? 如同settimer(),it_value用于指定當前的定時器到期時間。當定時器到期,it_value的值會被更新成it_interval 的值。如果it_interval的值為0,則定時器不是一個時間間隔定時器,一旦it_value到期就會回到未啟動狀態。timespec的結構提供了納秒級分辨率:
struct timespec{
??? time_t tv_sec;
??? long tv_nsec;??
};
??? 如果flags的值為TIMER_ABSTIME,則value所指定的時間值會被解讀成絕對值(此值的默認的解讀方式為相對于當前的時間)。這個經修改的行為可避免取得當前時間、計算“該時間”與“所期望的未來時間”的相對差額以及啟動定時器期間造成競爭條件。
??? 如果ovalue的值不是NULL,則之前的定時器到期時間會被存入其所提供的itimerspec。如果定時器之前處在未啟動狀態,則此結構的成員全都會被設定成0。
?
?
獲得一個活動定時器的剩余時間:
int?timer_gettime(timer_t?timerid,struct?itimerspec?*value);
?
取得一個定時器的超限運行次數:
??? 有可能一個定時器到期了,而同一定時器上一次到期時產生的信號還處于掛起狀態。在這種情況下,其中的一個信號可能會丟失。這就是定時器超限。程序可以通過調用timer_getoverrun來確定一個特定的定時器出現這種超限的次數。定時器超限只能發生在同一個定時器產生的信號上。由多個定時器,甚至是那些使用相同的時鐘和信號的定時器,所產生的信號都會排隊而不會丟失。
int?timer_getoverrun(timer_t?timerid);
??? 執行成功時,timer_getoverrun()會返回定時器初次到期與通知進程(例如通過信號)定時器已到期之間額外發生的定時器到期次數。舉例來說,在我們之前的例子中,一個1ms的定時器運行了10ms,則此調用會返回9。如果超限運行的次數等于或大于DELAYTIMER_MAX,則此調用會返回DELAYTIMER_MAX。
??? 執行失敗時,此函數會返回-1并將errno設定會EINVAL,這個唯一的錯誤情況代表timerid指定了無效的定時器。
?
刪除一個定時器:
int timer_delete (timer_t timerid);
??? 一次成功的timer_delete()調用會銷毀關聯到timerid的定時器并且返回0。執行失敗時,此調用會返回-1并將errno設定會 EINVAL,這個唯一的錯誤情況代表timerid不是一個有效的定時器。
?
例1:
void? handle()
{
?time_t t;
?char p[32];
?time(&t);
?strftime(p, sizeof(p), "%T", localtime(&t));
?printf("time is %sn", p);
}
?
int main()
{
?struct sigevent evp;
?struct itimerspec ts;
?timer_t timer;
?int ret;
?evp.sigev_value.sival_ptr = &timer;
?evp.sigev_notify = SIGEV_SIGNAL;
?evp.sigev_signo = SIGUSR1;
?signal(SIGUSR1, handle);
?ret = timer_create(CLOCK_REALTIME, &evp, &timer);
?if( ret )
??perror("timer_create");
?ts.it_interval.tv_sec = 1;
?ts.it_interval.tv_nsec = 0;
?ts.it_value.tv_sec = 3;
?ts.it_value.tv_nsec = 0;
?ret = timer_settime(timer, 0, &ts, NULL);
?if( ret )
??perror("timer_settime");
?while(1);
}
?
例2:
void? handle(union sigval v)
{
?time_t t;
?char p[32];
?time(&t);
?strftime(p, sizeof(p), "%T", localtime(&t));
?printf("%s thread %lu, val = %d, signal captured.n", p, pthread_self(), v.sival_int);
?return;
}
?
int main()
{
?struct sigevent evp;
?struct itimerspec ts;
?timer_t timer;
?int ret;
?memset?? (&evp,?? 0,?? sizeof?? (evp));
?evp.sigev_value.sival_ptr = &timer;
?evp.sigev_notify = SIGEV_THREAD;
?evp.sigev_notify_function = handle;
?evp.sigev_value.sival_int = 3;?? //作為handle()的參數
?ret = timer_create(CLOCK_REALTIME, &evp, &timer);
?if( ret)
??perror("timer_create");
?ts.it_interval.tv_sec = 1;
?ts.it_interval.tv_nsec = 0;
?ts.it_value.tv_sec = 3;
?ts.it_value.tv_nsec = 0;
?ret = timer_settime(timer, TIMER_ABSTIME, &ts, NULL);
?if( ret )
??perror("timer_settime");
?while(1);
}
總結
- 上一篇: 交通银行信用卡天使贷怎么收费
- 下一篇: WinCE流设备驱动简介及GPIO驱动的