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

posted @ 2020-09-21 17:15  wmate  阅读(1142)  评论(0编辑  收藏  举报