timer_create()(創建定時器)、timer_settime()(初始化定時器)以及timer_delete(銷毀它)


timer_create()、timer_settime()以及timer_delete

  最強大的定時器接口來自POSIX時鍾系列,其創建、初始化以及刪除一個定時器的行動被分為三個不同的函數:timer_create()(創建定時器)、timer_settime()(初始化定時器)以及timer_delete(銷毀它)。

一、創建一個定時器:

  int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)

  進程可以通過調用timer_create()創建特定的定時器,定時器是每個進程自己的,不是在fork時繼承的。該函數創建了定時器,並將他的ID 放入timerid指向的位置中。clock_id說明定時器是基於哪個時鍾的,*timerid裝載的是被創建的定時器的ID。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作為為一個參數。

  sigev_signo的值是SIGALRM以及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 %s/n", 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);

  } 

 

五、Linux 下取消用setitimer設置的定時器

Setitimer設置it_interval和it_value為零:

void uninit_time() 

{

    struct itimerval value; 

    value.it_value.tv_sec = 0; 

    value.it_value.tv_usec = 0; 

    value.it_interval = value.it_value; 

    setitimer(ITIMER_REAL, &value, NULL); 

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM