一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

淺析Linux應(yīng)用開(kāi)發(fā)之定時(shí)器

嵌入式應(yīng)用研究院 ? 來(lái)源:TLPI系統(tǒng)編程筆記 ? 2023-04-27 15:29 ? 次閱讀

間隔定時(shí)器

#include 

int 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í)間:

#include 

int 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()

#include 

unsigned 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()

#include 

unsigned 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()

#include 

int 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í)鐘的值

#include 

int 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í)符:

010dcbf8-e4cc-11ed-ab56-dac502259ad0.png

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
#include 

int 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
#include 

int 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
#include 

int 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 字段的值:

0119f680-e4cc-11ed-ab56-dac502259ad0.png

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
#include 

int 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
#include 

int 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
#include 

int 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
#include 

int 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í)器的到期通知。

#include 

int 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)的資源

#include 

int 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)

#include 

int 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)記為可讀。





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bà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)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Linux驅(qū)動(dòng)開(kāi)發(fā)-內(nèi)核定時(shí)器

    內(nèi)核定時(shí)器是內(nèi)核用來(lái)控制在未來(lái)某個(gè)時(shí)間點(diǎn)(基于jiffies(節(jié)拍總數(shù)))調(diào)度執(zhí)行某個(gè)函數(shù)的一種機(jī)制,相關(guān)函數(shù)位于 和 kernel/timer.c 文件
    的頭像 發(fā)表于 09-17 15:06 ?1637次閱讀

    手把手教你寫(xiě)Linux設(shè)備驅(qū)動(dòng)---定時(shí)器(一)(基于友善臂4412開(kāi)發(fā)板)

    手把手教你寫(xiě)Linux設(shè)備驅(qū)動(dòng)---定時(shí)器(一)(基于友善臂4412開(kāi)發(fā)板)
    發(fā)表于 12-02 15:59

    Linux下實(shí)時(shí)定時(shí)器的實(shí)現(xiàn)及應(yīng)用

    在嵌入式平臺(tái)的開(kāi)發(fā)過(guò)程中,由于控制硬件的要求,常常需要提供精度在μs級(jí)的定時(shí)器;而linux內(nèi)核由于采用了分時(shí)系統(tǒng),一般不提供這種級(jí)別的定時(shí)器。筆者在
    發(fā)表于 04-16 09:19 ?36次下載

    學(xué)單片機(jī)定時(shí)器部分

    帶您從零學(xué)單片機(jī)定時(shí)器部分 課程簡(jiǎn)介1定時(shí)器/計(jì)數(shù)簡(jiǎn)介2定時(shí)器/計(jì)數(shù)特殊功能寄存
    發(fā)表于 02-10 14:20 ?49次下載

    【實(shí)驗(yàn)38】定時(shí)器定時(shí)

    HL配套C實(shí)驗(yàn)例程100例定時(shí)器定時(shí),配合開(kāi)發(fā)板學(xué)習(xí)效果更好。
    發(fā)表于 04-11 16:09 ?7次下載

    HL配套C實(shí)驗(yàn)例程100例定時(shí)器定時(shí)常用參數(shù)

    HL配套C實(shí)驗(yàn)例程100例定時(shí)器定時(shí)常用參數(shù),配合開(kāi)發(fā)板學(xué)習(xí)效果更好。
    發(fā)表于 04-11 16:09 ?3次下載

    PIC32系列參考手冊(cè)定時(shí)器

    本文主要介紹了PIC32系列參考手冊(cè)定時(shí)器。
    發(fā)表于 06-06 17:29 ?9次下載

    PIC32系列參考手冊(cè)看門(mén)狗定時(shí)器、程序監(jiān)控定時(shí)器和上電延時(shí)定時(shí)器

    本文主要介紹了PIC32系列參考手冊(cè)看門(mén)狗定時(shí)器、程序監(jiān)控定時(shí)器和上電延時(shí)定時(shí)器。
    發(fā)表于 06-06 17:29 ?15次下載

    STM32定時(shí)器-基本定時(shí)器

    目錄定時(shí)器分類(lèi)基本定時(shí)器功能框圖講解基本定時(shí)器功能時(shí)鐘源計(jì)數(shù)時(shí)鐘計(jì)數(shù)自動(dòng)重裝載寄存
    發(fā)表于 11-23 18:21 ?32次下載
    STM32<b class='flag-5'>定時(shí)器</b>-基本<b class='flag-5'>定時(shí)器</b>

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

    ESP32 ESP-IDF 學(xué)習(xí)筆記(三)【通用硬件定時(shí)器(Timer)】文章目錄ESP32 ESP-IDF 學(xué)習(xí)筆記(三)【通用硬件定時(shí)器(Timer)】通用硬件
    發(fā)表于 11-26 11:36 ?38次下載
    ESP32 <b class='flag-5'>之</b> ESP-IDF 教學(xué)(三)——通用硬件<b class='flag-5'>定時(shí)器</b>(Timer)

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

    Linux發(fā)燒友1.RTOS篇1.1RT-Thread簡(jiǎn)介1.2時(shí)鐘管理1.2.1時(shí)鐘節(jié)拍1.3獲取系統(tǒng)節(jié)拍1.4定時(shí)器分類(lèi)1.5定時(shí)器源碼分析1.6定時(shí)器相關(guān)函數(shù)1.61動(dòng)態(tài)創(chuàng)建一個(gè)
    發(fā)表于 01-17 09:31 ?4次下載
    詳細(xì)剖析<b class='flag-5'>Linux</b>和RTOS(RT-Thread)的時(shí)鐘和<b class='flag-5'>定時(shí)器</b>的使用

    淺析怎么在Linux上使用cron定時(shí)器

    如何在 Linux 上使用 cron 定時(shí)器 1創(chuàng)建一個(gè) cronjob 要?jiǎng)?chuàng)建一個(gè) cronjob,你可以使用 crontab 命令,并添加 -e 選項(xiàng)。
    的頭像 發(fā)表于 01-30 11:37 ?1467次閱讀

    簡(jiǎn)單的555定時(shí)器項(xiàng)目電子蠟燭

    電子發(fā)燒友網(wǎng)站提供《簡(jiǎn)單的555定時(shí)器項(xiàng)目電子蠟燭.zip》資料免費(fèi)下載
    發(fā)表于 07-11 15:34 ?7次下載
    簡(jiǎn)單的555<b class='flag-5'>定時(shí)器</b>項(xiàng)目<b class='flag-5'>之</b>電子蠟燭

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

    正點(diǎn)原子的示波器能不能支撐嵌入式開(kāi)發(fā)流程。 Linux高精度定時(shí)器說(shuō)明 其實(shí)傳統(tǒng)的低分辨率定時(shí)器隨著技術(shù)的演進(jìn),已經(jīng)無(wú)法滿(mǎn)足開(kāi)發(fā)需求。而且硬
    的頭像 發(fā)表于 08-09 11:17 ?2206次閱讀

    Linux內(nèi)核定時(shí)器

    Linux內(nèi)核中,也可以通過(guò)定時(shí)器來(lái)完成定時(shí)功能。但和單片機(jī)不同的是,Linux內(nèi)核定時(shí)器是一種基于未來(lái)時(shí)間點(diǎn)的計(jì)時(shí)方式,它以當(dāng)前時(shí)刻為啟
    的頭像 發(fā)表于 09-22 08:56 ?2232次閱讀
    <b class='flag-5'>Linux</b>內(nèi)核<b class='flag-5'>定時(shí)器</b>