間隔定時(shí)器
#includeint setitimer(int which,const struct itimerval* new_value,struct itimerval* old_value);
setitimer() 創(chuàng)建一個(gè)間隔式定時(shí)器,這種定時(shí)器會(huì)在未來(lái)某個(gè)時(shí)間點(diǎn)到期,并于此后(可選擇地)每間隔一段時(shí)間到期一次
which 可以指定以下值:
ITIMER_REAL :創(chuàng)建以真實(shí)時(shí)間倒計(jì)時(shí)的定時(shí)器,到期會(huì)產(chǎn)生 SIGALARM 信號(hào)并發(fā)送給進(jìn)程
ITIMER_VIRTUAL:創(chuàng)建以進(jìn)程虛擬時(shí)間(用戶(hù)模式下的 CPU 時(shí)間) 倒計(jì)時(shí)的定時(shí)器,到期時(shí)會(huì)產(chǎn)生信號(hào) SIGVTALRM
ITIMER_PROF:創(chuàng)建一個(gè) profiling 定時(shí)器,以進(jìn)程時(shí)間(用戶(hù)態(tài)與內(nèi)核態(tài) CPU 時(shí)間的總和)倒計(jì)時(shí),到期時(shí),則會(huì)產(chǎn)生 SIGPROF 信號(hào)
針對(duì)所有這些信號(hào)的默認(rèn)處置均會(huì)終止進(jìn)程,除非真地期望如此,否則就需要針對(duì)這些定時(shí)器信號(hào)創(chuàng)建處理器函數(shù)。
struct itimerval{ struct timeval it_interval; /* Interval for periodic timer */ struct timeval it_value; /* Current value(time until next expiration) */ }; struct timeval{ time_t tv_sec; /* Seconds */ suseconds_t tv_usec; /* Microseconds */ };
new_value 下屬的 it_value 指定了距離定時(shí)器到期的延遲時(shí)間,it_interval 則說(shuō)明該定時(shí)器是否是周期性定時(shí)器,如果 it_interval 的兩個(gè)字段都是 0,那么該定時(shí)器屬于 it_value 所指定的時(shí)間間隔后到期的一次性定時(shí)器,只要 it_interval 中的任一字段非0,那么在每次定時(shí)器到期之后,都會(huì)將定時(shí)器重置為在指定間隔后再次到期
進(jìn)程只能擁有上述3種定時(shí)器的一種,當(dāng)?shù)诙握{(diào)用 settimer() 時(shí),修改已有定時(shí)器的屬性要符合參數(shù) which 中的類(lèi)型,如果調(diào)用 setitimer() 時(shí)將 new_value.it_value 的兩個(gè)字段均設(shè)置為 0,那么會(huì)屏蔽任何已有的定時(shí)器
若 old_value 不為 NULL,則以其所指向的 itimerval 結(jié)構(gòu)來(lái)返回定時(shí)器的前一設(shè)置:
如果 old_value.it_value 的兩個(gè)字段值均為 0,那么該定時(shí)器之前被設(shè)置處于屏蔽狀態(tài)
如果 old_value.it_interval 的兩個(gè)字段值均為 0,那么該定時(shí)器之前被設(shè)置為歷經(jīng) old_value.it_value 指定時(shí)間到期的一次性定時(shí)器
對(duì)需要在新定時(shí)器到期后將其還原的情況而言,獲取定時(shí)器的前一設(shè)置就很重要,如果不關(guān)心定時(shí)器的前一設(shè)置,可以將 old_value 設(shè)置為 NULL
定時(shí)器會(huì)從初始值 it_value 倒計(jì)時(shí)一直到 0 為止,遞減為 0 時(shí),會(huì)將相應(yīng)信號(hào)發(fā)送給進(jìn)程,隨后,如果時(shí)間間隔值 it_interval 非0,那么會(huì)再次將 it_value 加載到定時(shí)器,重新開(kāi)始向 0 倒計(jì)時(shí)
可以在任何時(shí)刻調(diào)用 getitimer(),以了解定時(shí)器的當(dāng)前狀態(tài),距離下次到期的剩余時(shí)間:
#includeint getitimer(int which,struct itimerval* curr_value);
getitimer() 返回由 which 指定定時(shí)器的當(dāng)前狀態(tài),并置于 curr_value 指向的緩沖區(qū)中
使用 setitimer() 和 alarm() 創(chuàng)建的定時(shí)器可以跨越 exec() 調(diào)用而得以保存,但由 fork() 創(chuàng)建的子進(jìn)程并不繼承該定時(shí)器。
更為簡(jiǎn)單的定時(shí)器接口:alarm()
#includeunsigned int alarm(unsigned int seconds);
seconds 表示定時(shí)器到期的秒數(shù),到期時(shí)向調(diào)用進(jìn)程發(fā)送 SIGALRM 信號(hào)
調(diào)用 alarm() 會(huì)覆蓋對(duì)定時(shí)器的前一個(gè)設(shè)置,調(diào)用 alarm(0) 可以屏蔽現(xiàn)有定時(shí)器
返回值是定時(shí)器前一設(shè)置距離到期的剩余描述,如果之前并無(wú)設(shè)置,則返回 0
setitimer() 和 alarm() 之間的交互
Linux 中 alarm() 和 setitimer() 針對(duì)同一進(jìn)程共享一個(gè)實(shí)時(shí)定時(shí)器,無(wú)論調(diào)用兩者之中的哪個(gè)完成了對(duì)定時(shí)器的前一設(shè)置,同樣可以調(diào)用二者中的任一函數(shù)來(lái)改變這一設(shè)置。
程序設(shè)置實(shí)時(shí)定時(shí)器時(shí),最好選用二者之一。
定時(shí)器的調(diào)度和精度
內(nèi)核配置項(xiàng) CONFIG_HIGH_RES_TIMERS 可以支持高分辨率定時(shí)器,使得定時(shí)器的精度不受軟件時(shí)鐘周期的影響,可以達(dá)到底層硬件所支持的精度,在現(xiàn)代硬件平臺(tái)上,精度達(dá)到微秒級(jí)別是司空見(jiàn)慣的。
為阻塞操作設(shè)置超時(shí)
實(shí)時(shí)定時(shí)器的用途之一就是為某個(gè)阻塞系統(tǒng)調(diào)用設(shè)置其處于阻塞狀態(tài)的時(shí)間上限。
例如,處理 read() 操作:
調(diào)用 sigaction() 創(chuàng)建 SIGALRM 信號(hào)的處置函數(shù),排除 SA_RESTART 標(biāo)志以確保系統(tǒng)調(diào)用不會(huì)重新啟動(dòng)
調(diào)用 alarm() 或者 setitimer() 創(chuàng)建定時(shí)器,設(shè)置超時(shí)時(shí)間
執(zhí)行阻塞的系統(tǒng)調(diào)用
系統(tǒng)調(diào)用返回,再次調(diào)用 alarm() 或 setitimer() 屏蔽定時(shí)器
檢查系統(tǒng)調(diào)用失敗是否設(shè)置 errno 為 EINTR ,即系統(tǒng)調(diào)用遭到中斷
暫停運(yùn)行一段固定時(shí)間
低分辨率休眠:sleep()
#includeunsigned int sleep(unsigned int seconds);
sleep() 可以暫停調(diào)用進(jìn)程執(zhí)行 seconds 秒,或者在捕獲信號(hào)后恢復(fù)進(jìn)程的執(zhí)行
如果休眠正常結(jié)束,返回0,如果因信號(hào)中斷休眠,返回剩余的秒數(shù)
考慮到一致性,應(yīng)該避免 sleep() 和 alarm() 以及 setitimer() 之間的混用,Linux 將 sleep() 實(shí)現(xiàn)為對(duì) nanosleep() 的調(diào)用,而有些老系統(tǒng)使用 alarm() 和 SIGALRM 信號(hào)處理函數(shù)實(shí)現(xiàn) sleep()
高分辨率休眠 nanosleep()
#includeint nanosleep(const struct timespec *req, struct timespec *rem);
nanosleep() 與 sleep() 相似,但是分辨率更高
struct timespec:
struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ };
規(guī)范規(guī)定不得使用信號(hào)實(shí)現(xiàn)該函數(shù),這意味著 nanosleep() 與 alarm() 和 setitimer() 混用,也不會(huì)危及程序的可移植性
盡管 nanosleep() 沒(méi)有使用信號(hào),但還是可以通過(guò)信號(hào)處理器函數(shù)將其中斷,此時(shí)將返回 -1,并設(shè)置錯(cuò)誤 EINTR,如果 remain 不為 NULL,則該指針?biāo)赶虻木彌_區(qū)將返回剩余的休眠時(shí)間,可以利用這個(gè)返回值重啟該系統(tǒng)調(diào)用以完成休眠,但是由于返回的 remain 時(shí)間未必是軟件時(shí)鐘間隔的整數(shù)倍,故而每次重啟都會(huì)遭受取整,其結(jié)果是,每次重啟后的休眠時(shí)間都要長(zhǎng)于前一調(diào)用返回的 remain 值,在信號(hào)接收頻率很高的情況下,進(jìn)程的休眠可能永遠(yuǎn)也結(jié)束不了,使用 TIMER_SBSTIME 選項(xiàng)的 clock_nanosleep() 可以避免這個(gè)問(wèn)題
POSIX 時(shí)鐘
Linux 中需要使用 realtime,實(shí)時(shí)函數(shù)庫(kù),需要鏈接 librt 即需要加入 -lrt 選項(xiàng)。
獲取時(shí)鐘的值
#includeint clock_getres(clockid_t clk_id, struct timespec *res); int clock_gettime(clockid_t clk_id, struct timespec *tp);
clock_gettime() 針對(duì)參數(shù) clk_id 所指定的時(shí)鐘返回時(shí)間,返回的時(shí)間,置于 tp 指向的結(jié)構(gòu)中
clockid_t 是 SUSv3 規(guī)范定義的數(shù)據(jù)類(lèi)型,用于表示時(shí)鐘標(biāo)識(shí)符:
CLOCK_REALTIME 時(shí)鐘是一種系統(tǒng)級(jí)時(shí)鐘,用于度量真實(shí)時(shí)間,它的設(shè)置是可以變更的
CLOCK_MONOTONIC 時(shí)鐘對(duì)時(shí)間的度量始于"未予規(guī)范的過(guò)去某一時(shí)間點(diǎn)",系統(tǒng)啟動(dòng)后就不會(huì)改變它,Linux 上,這種時(shí)鐘對(duì)時(shí)間的測(cè)量始于系統(tǒng)啟動(dòng)
CLOCK_PROCESS_CPUTIME_ID 時(shí)鐘測(cè)量調(diào)用進(jìn)程所消耗的用戶(hù)和系統(tǒng) CPU 時(shí)間
CLOCK_THREAD_CPUTIME_ID 時(shí)鐘測(cè)量調(diào)用線程所消耗的用戶(hù)和系統(tǒng) CPU 時(shí)間
設(shè)置時(shí)鐘的值
#define _POSIX_C_SOURCE 199309L #includeint clock_settime(clockid_t clk_id, const struct timespec *tp);
clock_settime() 利用 tp 指向緩沖區(qū)中的時(shí)間來(lái)設(shè)置由 clockid 指定的時(shí)鐘
如果 tp 指向的時(shí)間并非 clock_getres() 所返回的時(shí)鐘分辨率的整數(shù)倍,時(shí)間會(huì)向下取整
特權(quán)級(jí)進(jìn)程可以設(shè)置 CLOCK_REALTIME 時(shí)鐘,該時(shí)鐘的初始值通常自 Epoch 以來(lái)的時(shí)間,其他時(shí)鐘類(lèi)型不可更改
獲取特定進(jìn)程或線程的時(shí)鐘 ID
要測(cè)量特定進(jìn)程或線程消耗的 CPU 時(shí)間,首先要獲取其時(shí)鐘 ID:
#define _XOPEN_SOURCE 600 #includeint clock_getcpuclockid(pid_t pid, clockid_t *clock_id);
clock_getcpuclockid 將隸屬于 pid 進(jìn)程的 CPU 時(shí)間時(shí)鐘的標(biāo)識(shí)符置于 clock_id 指針指向的緩沖區(qū)中
#define _XOPEN_SOURCE 600 #include#include int pthread_getcpuclockid(pthread_t thread, clockid_t *clock_id);
pthread_getcpuclockid() 是 clock_getcpuclockid() 的 POSIX 線程版,返回的標(biāo)識(shí)符所標(biāo)識(shí)的時(shí)鐘用于度量調(diào)用進(jìn)程中指定線程消耗的 CPU 時(shí)間
高分辨率休眠的改進(jìn)版
#define _XOPEN_SOURCE 600 #includeint clock_nanosleep(clockid_t clock_id, int flags,const struct timespec *request,struct timespec *remain);
默認(rèn)情況下,flags 是0,request 指定的休眠間隔時(shí)間是相對(duì)時(shí)間,如果 flags 設(shè)置為 TIMER_ABSTIME ,request 則表示 clock_id 所測(cè)量的絕對(duì)時(shí)間,這個(gè)特性對(duì)于需要精確休眠一段指定時(shí)間的應(yīng)用程序至關(guān)重要,以相對(duì)時(shí)間進(jìn)行休眠,進(jìn)程可能執(zhí)行到一半就被占先了,結(jié)果休眠的時(shí)間要比預(yù)期的久
對(duì)于那些被信號(hào)處理器中斷并使用循環(huán)重啟休眠的進(jìn)程來(lái)說(shuō),"嗜睡" 問(wèn)題尤其明顯,如果以高頻接收信號(hào),那么按相對(duì)時(shí)間休眠的進(jìn)程在休眠時(shí)間上會(huì)有較大誤差,可以通過(guò)如下方式避免嗜睡:
先調(diào)用 clock_gettime() 獲取時(shí)間,再加上期望休眠的時(shí)間量
再以 TIMER_ABSTIME 標(biāo)志調(diào)用 clock_nanosleep() 函數(shù),指定了 TIME_ABSTIME 時(shí),不需要使用參數(shù) remain
信號(hào)處理器程序中斷了 clock_nanosleep() 調(diào)用,再次調(diào)用該函數(shù)來(lái)重啟休眠時(shí),request 參數(shù)不變
struct timespec request; if(clock_gettime(CLOCK_REALTIME,&request) == -1) errExit("clock_gettime"); request.tv_sec += 20; /* sleep for 20 seconds from now*/ s = clock_nanosleep(CLOCK_REALTIME,TIMER_ABSTIME,&request,NULL); if(s != 0) { if(s == EINTR) printf("Interrupted by signal handler "); else errExit("clock_nanosleep"); }
POSIX 間隔式定時(shí)器
使用 settimer() 來(lái)設(shè)置經(jīng)典 UNIX 間隔式定時(shí)器,會(huì)收到如下制約:
針對(duì) ITIMER_REAL,ITIMER_VIRTUAL 和 ITIMER_PROF 這 3 類(lèi)定時(shí)器,每種智能設(shè)置一個(gè)
只能通過(guò)發(fā)送信號(hào)的方式通知定時(shí)器到期,另外也不能改變到期時(shí)產(chǎn)生的信號(hào)
如果一個(gè)間隔式定時(shí)器到期多次,且相應(yīng)信號(hào)遭到阻塞時(shí),那么會(huì)只調(diào)用一次信號(hào)處理器函數(shù),換言之,無(wú)從知曉是否出現(xiàn)定時(shí)器溢出的情況
定時(shí)器的分辨率只能達(dá)到微秒級(jí)
POSIX.1b 定義了一套 API 來(lái)突破這些限制,主要包含如下幾個(gè)階段:
timer_create() 創(chuàng)建一個(gè)新的定時(shí)器,并定義其到期時(shí)對(duì)進(jìn)程的通知方法
timer_settime() 啟動(dòng)或者停止一個(gè)定時(shí)器
timer_delete() 刪除不再需要使用的定時(shí)器
fork() 創(chuàng)建的子進(jìn)程不會(huì)繼承 POSIX 定時(shí)器,調(diào)用 exec() 期間亦或是進(jìn)程終止時(shí)將停止并刪除定時(shí)器。
使用 POSIX 定時(shí)器的 API 程序編譯時(shí)需要使用 -lrt 選項(xiàng)。
創(chuàng)建定時(shí)器
#define _POSIX_C_SOURCE 199309L #include#include int timer_create(clockid_t clockid, struct sigevent *sevp,timer_t *timerid);
timer_create() 創(chuàng)建一個(gè)新的定時(shí)器,并以 clockid 指定的時(shí)鐘進(jìn)行時(shí)間度量
clockid 可以是 SUSv3 規(guī)范定義的類(lèi)型,也可以采用 clock_getcpuclockid() 或 pthread_getcpuclockid() 返回的 clockid 值
函數(shù)返回時(shí),timerid 指向的緩沖區(qū)放置定時(shí)器句柄,供后續(xù)調(diào)用中指代該定時(shí)器之用
sevp 可決定定時(shí)器到期時(shí),對(duì)應(yīng)應(yīng)用程序的通知方式,指向 struct sigevent:
union sigval { /* Data passed with notification */ int sival_int; /* Integer value */ void *sival_ptr; /* Pointer value */ }; struct sigevent { int sigev_notify; /* Notification method */ int sigev_signo; /* Notification signal */ union sigval sigev_value; /* Data passed with notification */ void (*sigev_notify_function) (union sigval); /* Function used for thread notification (SIGEV_THREAD) */ void *sigev_notify_attributes; /* Attributes for notification thread (SIGEV_THREAD) */ pid_t sigev_notify_thread_id; /* ID of thread to signal (SIGEV_THREAD_ID) */ };
sigev_notify 字段的值:
SIGEV_NONE:不提供定時(shí)器的到期通知,進(jìn)程可以使用 timer_gettime() 來(lái)監(jiān)控定時(shí)器的運(yùn)轉(zhuǎn)情況
SIGEV_SIGNAL:定時(shí)器到期時(shí),為進(jìn)程生成指定于 sigev_signo 中的信號(hào),如果 sigev_signal 為實(shí)時(shí)信號(hào),那么 sigev_value 字段則指定了信號(hào)的伴隨數(shù)據(jù),通過(guò) siginfo_t 結(jié)構(gòu)的 si_value 可獲取這一數(shù)據(jù)
SIGEV_THREAD:定時(shí)器到期時(shí),會(huì)調(diào)用由 sigev_notify_function 字段指定的函數(shù),調(diào)用該函數(shù)類(lèi)似于調(diào)用新線程的啟動(dòng)函數(shù)
SIGEV_THREAD_ID:與 SIGEV_THREAD 相類(lèi)似,只是發(fā)送信號(hào)的目標(biāo)線程 ID 要與 sigev_notify_thread_id 相匹配
配備和解除定時(shí)器
#define _POSIX_C_SOURCE 199309L #includeint timer_settime(timer_t timerid, int flags,const struct itimerspec *new_value,struct itimerspec *old_value);
timer_settime() 的參數(shù) timerid 是一個(gè)定時(shí)器句柄,由之前對(duì) timer_create() 的調(diào)用返回
new_value 包含定時(shí)器的新設(shè)置,old_value 返回定時(shí)器的前一設(shè)置,如果對(duì)前一個(gè)設(shè)置不感興趣,可以設(shè)置為 NULLL
struct timespec { time_t tv_sec; /* Seconds */ long tv_nsec; /* Nanoseconds */ }; struct itimerspec { struct timespec it_interval; /* Timer interval */ struct timespec it_value; /* Initial expiration */ };
it_value 指定了定時(shí)器首次到期的時(shí)間,it_interval 任意一個(gè)字段非0,那么就是一個(gè)周期性定時(shí)器,如果都是0,那么這個(gè)定時(shí)器將只到期一次
flags 如果是0,會(huì)將 value.it_value 視為始于 timer_settime() 調(diào)用時(shí)間點(diǎn)的相對(duì)值,如果 flags 設(shè)為 TIMER_ABSTIME,那么 value.it_value 則是一個(gè)絕對(duì)時(shí)間
為了啟動(dòng)定時(shí)器,需要調(diào)用函數(shù) timer_settime(),并將 value.it_value 的一個(gè)或者全部字段設(shè)置為非0,如果之前曾經(jīng)配備過(guò)定時(shí)器,則 timer_settime() 會(huì)將之前的設(shè)置值替換掉
如果定時(shí)器的值和間隔時(shí)間并非對(duì)應(yīng)時(shí)鐘分辨率的整數(shù)倍,那么會(huì)對(duì)這些值向上取整
要解除定時(shí)器,需要調(diào)用 timer_settime(),并將 value.it_value 的所有字段設(shè)置為 0
獲取定時(shí)器的當(dāng)前值
#define _POSIX_C_SOURCE 199309L #includeint timer_gettime(timer_t timerid, struct itimerspec *curr_value);
timer_gettime() 返回由 timerid 指定的 POSIX 定時(shí)器的間隔以及剩余時(shí)間
如果返回結(jié)構(gòu) curr_value.it_value 的兩個(gè)字段都是0,表示定時(shí)器處于停止?fàn)顟B(tài),如果 curr_value.it_interval 的兩個(gè)字段都是0,那么該定時(shí)器僅在 curr_value.it_value 給定的時(shí)間到期過(guò)一次
刪除定時(shí)器
每個(gè) POSIX 定時(shí)器都會(huì)消耗少量的系統(tǒng)資源,一旦使用完畢,應(yīng)當(dāng)及時(shí)釋放這些資源:
#define _POSIX_C_SOURCE 199309L #includeint timer_delete(timer_t timerid);
對(duì)于已啟動(dòng)的定時(shí)器,會(huì)在移除之前自動(dòng)將其停止
進(jìn)程終止時(shí),會(huì)自動(dòng)刪除所有定時(shí)器
通過(guò)信號(hào)發(fā)出通知
如果選擇通過(guò)信號(hào)來(lái)接收定時(shí)器通知,那么處理這些信號(hào)時(shí)既可以采用信號(hào)處理器函數(shù),也可以調(diào)用 sigwaitinfo() 或是 sigtimerdwait()。接收進(jìn)程借助于這兩種方法可以獲取一個(gè) siginfo_t 結(jié)構(gòu):
si_signo:包含由定時(shí)器產(chǎn)生的信號(hào)
si_code:置為 SI_TIMER,表示這是因?yàn)?POSIX 定時(shí)器到期而產(chǎn)生的信號(hào)
si_value:設(shè)置為以 timer_create()創(chuàng)建定時(shí)器在 evp.sigev_value 中提供的值
為 evp.sigev_value 指定不同的值,可以將到期時(shí)發(fā)送同類(lèi)信號(hào)的不同定時(shí)器區(qū)分開(kāi)。
Linux 還為 siginfo_t 結(jié)構(gòu)提供了如下非標(biāo)準(zhǔn)字段:
si_overrun:包含了定時(shí)器溢出個(gè)數(shù)
定時(shí)器溢出
假設(shè)已經(jīng)選擇通過(guò)信號(hào)傳遞的方式來(lái)接收定時(shí)器到期的通知。在捕獲或接收相關(guān)信號(hào)之前定時(shí)器到期多次,或者不論直接調(diào)用 sigprocmask() 還是在信號(hào)處理器函數(shù)中暗中處理,也都有可能堵塞相關(guān)信號(hào)的發(fā)送,那如何知道這些定時(shí)器溢出?
接收到定時(shí)器信號(hào)之后,有兩種方法可以獲取定時(shí)器的溢出值:
調(diào)用 timer_getoverrun()
使用隨信號(hào)一同返回的結(jié)構(gòu) siginfo_t 中的 si_overrun 字段值,這種方法可以避免 timer_getoverrun() 調(diào)用開(kāi)銷(xiāo),但是這種方法是 Linux 擴(kuò)展方法,無(wú)法移植
#define _POSIX_C_SOURCE 199309L #includeint timer_getoverrun(timer_t timerid);
每次收到定時(shí)器信號(hào)后,都會(huì)重置定時(shí)器溢出計(jì)數(shù),若自處理或接收定時(shí)器信號(hào)之后,定時(shí)器僅到期一次,則溢出計(jì)數(shù)為 0
返回由參數(shù) timerid 指定的定時(shí)器的溢出值
timer_getoverrun() 是異步信號(hào)安全的函數(shù),故而在信號(hào)處理器函數(shù)內(nèi)部調(diào)用也是安全的
通過(guò)線程來(lái)通知
SIGEV_THREAD 標(biāo)志允許程序從一個(gè)獨(dú)立的線程中調(diào)用函數(shù)來(lái)獲取定時(shí)器到期通知。
利用文件描述符進(jìn)行通知的定時(shí)器
Linux 內(nèi)核特有的創(chuàng)建定時(shí)器的 timerfd API,可從文件描述符中讀取其所創(chuàng)建定時(shí)器的到期通知。
#includeint timerfd_create(int clockid, int flags);
timerfd_create() 創(chuàng)建一個(gè)新的定時(shí)器對(duì)象,并返回一個(gè)指代該對(duì)象的文件描述符
clockid 的值,可以是:CLOCK_REALTIME 或者 CLOCK_MONOTONIC
flags 最初必須設(shè)置為0現(xiàn)在支持:
TFD_CLOEXEC:為新的文件描述符設(shè)置運(yùn)行時(shí)關(guān)閉標(biāo)志 FD_CLOEXEC 與 open() 的 O_CLOEXEC 適用于相同的情況
TFD_NONBLOCK:為底層的打開(kāi)文件描述符設(shè)置 O_NONBLOCK 標(biāo)志,隨后的讀操作將是非阻塞的
timerfd_create() 創(chuàng)建的定時(shí)器使用完畢后,應(yīng)該調(diào)用 close() 關(guān)閉相應(yīng)的文件描述符,以便內(nèi)核釋放相應(yīng)的資源
#includeint timerfd_settime(int fd, int flags,const struct itimerspec *new_value,struct itimerspec *old_value);
timerfd_settime() 可以啟動(dòng)或解除由文件描述符 fd 指代的定時(shí)器
new_value 為指定的新設(shè)置,old_value 為前一設(shè)置,如果不關(guān)心前一個(gè)設(shè)置可以將其設(shè)置為 NULL
flags 參數(shù)可以是0,此時(shí)將 new_value.it_value 的值視為相對(duì)于調(diào)用 timerfd_settime() 的相對(duì)時(shí)間點(diǎn),也可以設(shè)置為 TFD_TIMER_ABSTIME 將其視為從時(shí)鐘0點(diǎn)開(kāi)始測(cè)量的絕對(duì)時(shí)間點(diǎn)
#includeint timerfd_gettime(int fd, struct itimerspec *curr_value);
timerfd_gettime() 返回文件描述符 fd 所標(biāo)識(shí)的定時(shí)器間隔和剩余時(shí)間
如果返回的 curr_value.it_value 字段都是0,那么該定時(shí)器已經(jīng)被解除,如果返回的結(jié)構(gòu) curr_value.it_interval 中的兩個(gè)字段都是0,那么定時(shí)器只會(huì)到期一次,到期時(shí)間在 curr_value.it_value 中給出
timerfd 與 fork() 以及 exec() 之間的交互
調(diào)用 fork() 期間,子進(jìn)程會(huì)繼承 timerfd_create() 所創(chuàng)建的文件描述符的拷貝。
timerfd_create() 創(chuàng)建額度文件描述符能夠跨越 exec() 得以保存,除非將描述符設(shè)置為運(yùn)行時(shí)關(guān)閉,已配備的定時(shí)器在 exec() 之后會(huì)繼承生成到期通知。
從 timerfd 文件描述符讀取
一旦以 timer_settime() 啟動(dòng)了定時(shí)器,就可以從相應(yīng)文件描述符中調(diào)用 read() 來(lái)讀取定時(shí)器的到期信息,處于這一目的,傳給 read() 的緩沖區(qū)必須滿(mǎn)足容納一個(gè) uint64_t 類(lèi)型的要求。
在上次使用 timerfd_settime() 修改設(shè)置以后,或者是最后一次執(zhí)行 read() 后,如果發(fā)生了一起或多起定時(shí)器到期時(shí)間,那么 read() 立即返回,返回的緩沖區(qū)中包含了到期的次數(shù)。
如果并無(wú)定時(shí)器到期,read() 將會(huì)阻塞至下一個(gè)到期。
也可以執(zhí)行 fcntl() 設(shè)置 O_NONBLOCK 標(biāo)志,這時(shí)的讀動(dòng)作將是非阻塞的,如果沒(méi)有定時(shí)器到期,則返回,設(shè)置錯(cuò)誤 EAGAIN。
可以使用 select(),poll() 和 epoll() 對(duì) timerfd 文件描述符進(jìn)行監(jiān)控,如果定時(shí)器到期,則將對(duì)應(yīng)的文件描述符標(biāo)記為可讀。
審核編輯:劉清
-
處理器
+關(guān)注
關(guān)注
68文章
19740瀏覽量
232864 -
定時(shí)器
+關(guān)注
關(guān)注
23文章
3272瀏覽量
116705 -
Linux開(kāi)發(fā)
+關(guān)注
關(guān)注
0文章
36瀏覽量
7188
原文標(biāo)題:Linux應(yīng)用開(kāi)發(fā)之定時(shí)器
文章出處:【微信號(hào):嵌入式應(yīng)用研究院,微信公眾號(hào):嵌入式應(yīng)用研究院】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
Linux驅(qū)動(dòng)開(kāi)發(fā)-內(nèi)核定時(shí)器
手把手教你寫(xiě)Linux設(shè)備驅(qū)動(dòng)---定時(shí)器(一)(基于友善之臂4412開(kāi)發(fā)板)
Linux下實(shí)時(shí)定時(shí)器的實(shí)現(xiàn)及應(yīng)用
學(xué)單片機(jī)之定時(shí)器部分
【實(shí)驗(yàn)38】定時(shí)器定時(shí)
HL配套C實(shí)驗(yàn)例程100例之定時(shí)器定時(shí)常用參數(shù)
PIC32系列參考手冊(cè)之看門(mén)狗定時(shí)器、程序監(jiān)控定時(shí)器和上電延時(shí)定時(shí)器
STM32定時(shí)器-基本定時(shí)器

ESP32 之 ESP-IDF 教學(xué)(三)——通用硬件定時(shí)器(Timer)

詳細(xì)剖析Linux和RTOS(RT-Thread)的時(shí)鐘和定時(shí)器的使用

淺析怎么在Linux上使用cron定時(shí)器
簡(jiǎn)單的555定時(shí)器項(xiàng)目之電子蠟燭

Linux驅(qū)動(dòng)開(kāi)發(fā)高精度定時(shí)器的精度測(cè)量評(píng)測(cè)
Linux內(nèi)核定時(shí)器

評(píng)論