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


免責聲明!

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



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