1. 程式人生 > 實用技巧 >linux應用層定時器的常用方法

linux應用層定時器的常用方法

一、alarm

如果不要求很精確的話,用 alarm() 和 signal() 就夠了。

unsigned int alarm(unsigned int seconds)

專門為SIGALRM訊號而設,在指定的時間seconds秒後,將向程序本身傳送SIGALRM訊號,又稱為鬧鐘時間。程序呼叫alarm後,任何以前的alarm()呼叫都將無效。如果引數seconds為零,那麼程序內將不再包含任何鬧鐘時間。如果呼叫alarm()前,程序中已經設定了鬧鐘時間,則返回上一個鬧鐘時間的剩餘時間,否則返回0。

示例:

#include <stdio.h>
#include <unistd.h>
#include 
<signal.h> void sigalrm_fn(int sig) { printf("alarm!\n"); alarm(2); return; } int main(void) { signal(SIGALRM, sigalrm_fn); alarm(2); while(1) pause(); }

二、setitimer

int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
int getitimer(int
which, struct itimerval *value); strcut timeval { long tv_sec; /**/ long tv_usec; /*微秒*/ }; struct itimerval { struct timeval it_interval; /*時間間隔*/ struct timeval it_value; /*當前時間計數*/ };

setitimer() 比 alarm() 功能強大,支援3種類型的定時器:

①ITIMER_REAL:給一個指定的時間間隔,按照實際的時間來減少這個計數,當時間間隔為0的時候發出SIGALRM訊號。
②ITIMER_VIRTUAL:給定一個時間間隔,當程序執行的時候才減少計數,時間間隔為0的時候發出SIGVTALRM訊號。
③ITIMER_PROF:給定一個時間間隔,當程序執行或者是系統為程序排程的時候,減少計數,時間到了,發出SIGPROF訊號。

setitimer() 第一個引數 which 指定定時器型別(上面三種之一);第二個引數是結構 itimerval 的一個例項;第三個引數可不做處理。

例子:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>


void sigroutine(int signo){
   switch (signo){
   case SIGALRM:
       printf("Catch a signal -- SIGALRM \n");
       signal(SIGALRM, sigroutine);
       break;
   case SIGVTALRM:
       printf("Catch a signal -- SIGVTALRM \n");
       signal(SIGVTALRM, sigroutine);
       break;
   }
   return;
}

int main()
{
   struct itimerval value, ovalue, value2;

   printf("process id is %d ", getpid());
   signal(SIGALRM, sigroutine);
   signal(SIGVTALRM, sigroutine);
   value.it_value.tv_sec = 1;
   value.it_value.tv_usec = 0;
   value.it_interval.tv_sec = 1;
   value.it_interval.tv_usec = 0;
   setitimer(ITIMER_REAL, &value, &ovalue);
   value2.it_value.tv_sec = 0;
   value2.it_value.tv_usec = 500000;
   value2.it_interval.tv_sec = 0;
   value2.it_interval.tv_usec = 500000;
   setitimer(ITIMER_VIRTUAL, &value2, &ovalue);
   for(;;);
}

三、用 sleep 以及 usleep 實現定時執行任務

#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

static char msg[] = "I received a msg.\n";
int len;

void show_msg(int signo)
{
    write(STDERR_FILENO, msg, len);
}

int main()
{
    struct sigaction act;
    union sigval tsval;
    act.sa_handler = show_msg;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction(50, &act, NULL);
    len = strlen(msg);
    while ( 1 )
    {
        sleep(2); /*睡眠2秒*/
        /*向主程序傳送訊號,實際上是自己給自己發訊號*/
        sigqueue(getpid(), 50, tsval);
    }
    return 0;
}

如果你只做一般的定時,到了時間去執行一個任務,這種方法是最簡單的。

四、使用 select 來提供精確定時和休眠

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

n 指監視的檔案描述符範圍,通常設為所要select的fd+1;readfds,writefds 和 exceptfds分別是讀,寫和異常檔案描述符集;timeout 為超時時間。

示例:

int msSleep(long ms) 
 {
    struct timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = ms;

    return select(0, NULL, NULL, NULL, &tv);
 }

setitimer 和 select 都能實現程序的精確休眠,這裡給出了一個簡單的基於 select 的實現。我不推薦使用 setitimer,因為 Linux 系統提供的 timer 有限(每個程序至多能設3個不同型別的 timer),而且 setitimer 實現起來沒有 select 簡單。

本文轉載自:https://blog.csdn.net/lu_embedded/article/details/53080496