如何实现linux下的定时器?

时间:2022-01-01 23:36:24
设置一个时间值,等到了的时候执行某个动作。然后又开始计时。
是循环的方式。

11 个解决方案

#1


sleep
alarm
都可以吧

#2


linux下的器定时作用的函数很多,比如常用的sleep()函数,这里不再过多说这个。主要说的关于定时器精度和循环定时器的应用,尤其是在多线程应用过程中所要注意的定时器问题。

1. alarm()和signal()函数

      alarm()函数在自己规定的时间到来时,向系统发送一个名为SIGALRM的信号,如果你想在自己规定的时间后运行一个函数,那么就是用 signal(int ,void*)函数,他的第一个参数是接收到的信号,比如说是SIGALRM,第二个参数是要运行的函数的地址,这样就达到了在某个时间后运行一个函数的目的。但是在多线程的程序里会出现差错,可以试一试如果发送一个信号后,有多个线程signal会出现什么差错。

2. setitimer()精确定时

    此函数可以达到微妙级别的定时(但要考路到内核HZ,不一定能达到),我们可以看一下他的参数

setitmer(int which, const struct itimerval *value, struct itimerval *ovalue)

第一个参数是信号类型具体可以查到,而itimerval结构体,就是定义触发时间的结构体,它包含两个参数 :一个是下次定时的时间取值(分为秒和微妙)一个是本次定时的设置,具体结构可以man 到。最后一个参数可以设置为NULL,此函数虽然达到了精确定时,但是在多线程里好像只能三个吧,(多指教),并且会产生与上面说的同一类问题如果你用 signal接受的话。

3. select()函数

     此函数使用在文件操作里面的,当然socket编程不会少了它,我在使用计时器时看到了网上使用它的一些例子,但是立即就放弃了,因为感觉很难似的,在操作文件编程时也没着重研究,过了几天学习socket并发编程时,又一次见到了她,这是才发现基本上是很简单的,尤其是用在计时器上,(教训啊)这里简单介绍一下相关计时器的编程,socket以后再说。

      好了,开始了:

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

看上去很难吧,O(∩_∩)O~,现在就看计时器了所以就把中间三个参数设成NULL,不用管,第一个参数设置成 0,最后一个就够体和上面的差不多:

struct timeval{

  long tv_sec; // seconds

  long tv_usec; // microseconds

  }

可以精确到微妙,可以了吧,设置上时间,比如 struct timeval time = { 1,30 },此时设置的是一秒30微妙,此时变成了:

select( 0, NULL, NULL,NULL,time),简单了吧,一个一秒30微妙的定时器了,每到时间了就触发了,好像没信号,也没什么特殊要求(比如不能超过三个),按道理来说是应该每隔一定时间就触发一次,但是在伯克利系统中(什么是伯克利啊?——自己查吧)他不是自动触发的要设置信号(用sigaction() 函数)这个不用管,好了,如果你就想定时一次,有一个就行了,但是你想每隔time一次 呢,好办 while(1){....select(....).....}无限循环不就可以了。

综合分析::

       sleep() alarm() 是精确到秒的,setitimer(),select()是精确到微妙的,还有一个是精确到纳秒的,但是由于系统内核的原因好像不是这么精确,微妙就不错了。

       setitmer()可以循环计时,其他不行,如果不是在多线程里没什么问题。

那么在多线程里会出什么问题呢:在多线程里信号时共享的,当然进程资源也是共享的,所以一个alarm(),setitimer()发信号都能收到,如果好几个线程都接手signal()那么就不能确定哪一个线程收到了信号,所以有随机性,那么怎样在多线程环境里设置定时器呢?这里说的是设置一个定时器,到时间了运行设定好的函数,这个问题下一篇来讲,当然系统有相应函数库,我说的是自己编出来了。

#3


第一种方法:
void startTimer()
{
    struct itimerval tick;
    int res;
    memset(&tick, 0, sizeof(tick));
    tick.it_value.tv_sec = 1;  // sec
    tick.it_value.tv_usec = 0; // micro sec.
    
    tick.it_interval.tv_sec = 0;
    tick.it_interval.tv_usec = MINTIMERINTERVAL*1000;
    signal(SIGALRM, timerFunc);
    res = setitimer(ITIMER_REAL, &tick, NULL);
    if (res) {
      DEBUG_ERR("Set timer failed!!\n");
    }

}


void timerFunc()
{
 //要实现的内容
}

第二种方法:
用一个线程来实现这种方法,

#4


while(1)
{
sleep(1);///睡1秒,linux下。
}

#5


2楼说的很详细了。

#6


如果不要求很精确的话,用 alarm() 和 signal() 就够了
代码:
/*
 * Example for alarm.
 */
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void sigalrm_fn(int sig)
{
        /* Do something */
        printf("alarm!\n");
        alarm(2);
        return;
}
int main(void)
{
        signal(SIGALRM, sigalrm_fn);
        alarm(2);
        /* Do someting */
        while(1) pause();
}

#7


#8


sleep() alarm() 是精确到秒的,setitimer(),select()是精确到微妙的

#9


ls的挖坟呀

#10


一天之后的话用crontab命令

#11


libevent

#1


sleep
alarm
都可以吧

#2


linux下的器定时作用的函数很多,比如常用的sleep()函数,这里不再过多说这个。主要说的关于定时器精度和循环定时器的应用,尤其是在多线程应用过程中所要注意的定时器问题。

1. alarm()和signal()函数

      alarm()函数在自己规定的时间到来时,向系统发送一个名为SIGALRM的信号,如果你想在自己规定的时间后运行一个函数,那么就是用 signal(int ,void*)函数,他的第一个参数是接收到的信号,比如说是SIGALRM,第二个参数是要运行的函数的地址,这样就达到了在某个时间后运行一个函数的目的。但是在多线程的程序里会出现差错,可以试一试如果发送一个信号后,有多个线程signal会出现什么差错。

2. setitimer()精确定时

    此函数可以达到微妙级别的定时(但要考路到内核HZ,不一定能达到),我们可以看一下他的参数

setitmer(int which, const struct itimerval *value, struct itimerval *ovalue)

第一个参数是信号类型具体可以查到,而itimerval结构体,就是定义触发时间的结构体,它包含两个参数 :一个是下次定时的时间取值(分为秒和微妙)一个是本次定时的设置,具体结构可以man 到。最后一个参数可以设置为NULL,此函数虽然达到了精确定时,但是在多线程里好像只能三个吧,(多指教),并且会产生与上面说的同一类问题如果你用 signal接受的话。

3. select()函数

     此函数使用在文件操作里面的,当然socket编程不会少了它,我在使用计时器时看到了网上使用它的一些例子,但是立即就放弃了,因为感觉很难似的,在操作文件编程时也没着重研究,过了几天学习socket并发编程时,又一次见到了她,这是才发现基本上是很简单的,尤其是用在计时器上,(教训啊)这里简单介绍一下相关计时器的编程,socket以后再说。

      好了,开始了:

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

看上去很难吧,O(∩_∩)O~,现在就看计时器了所以就把中间三个参数设成NULL,不用管,第一个参数设置成 0,最后一个就够体和上面的差不多:

struct timeval{

  long tv_sec; // seconds

  long tv_usec; // microseconds

  }

可以精确到微妙,可以了吧,设置上时间,比如 struct timeval time = { 1,30 },此时设置的是一秒30微妙,此时变成了:

select( 0, NULL, NULL,NULL,time),简单了吧,一个一秒30微妙的定时器了,每到时间了就触发了,好像没信号,也没什么特殊要求(比如不能超过三个),按道理来说是应该每隔一定时间就触发一次,但是在伯克利系统中(什么是伯克利啊?——自己查吧)他不是自动触发的要设置信号(用sigaction() 函数)这个不用管,好了,如果你就想定时一次,有一个就行了,但是你想每隔time一次 呢,好办 while(1){....select(....).....}无限循环不就可以了。

综合分析::

       sleep() alarm() 是精确到秒的,setitimer(),select()是精确到微妙的,还有一个是精确到纳秒的,但是由于系统内核的原因好像不是这么精确,微妙就不错了。

       setitmer()可以循环计时,其他不行,如果不是在多线程里没什么问题。

那么在多线程里会出什么问题呢:在多线程里信号时共享的,当然进程资源也是共享的,所以一个alarm(),setitimer()发信号都能收到,如果好几个线程都接手signal()那么就不能确定哪一个线程收到了信号,所以有随机性,那么怎样在多线程环境里设置定时器呢?这里说的是设置一个定时器,到时间了运行设定好的函数,这个问题下一篇来讲,当然系统有相应函数库,我说的是自己编出来了。

#3


第一种方法:
void startTimer()
{
    struct itimerval tick;
    int res;
    memset(&tick, 0, sizeof(tick));
    tick.it_value.tv_sec = 1;  // sec
    tick.it_value.tv_usec = 0; // micro sec.
    
    tick.it_interval.tv_sec = 0;
    tick.it_interval.tv_usec = MINTIMERINTERVAL*1000;
    signal(SIGALRM, timerFunc);
    res = setitimer(ITIMER_REAL, &tick, NULL);
    if (res) {
      DEBUG_ERR("Set timer failed!!\n");
    }

}


void timerFunc()
{
 //要实现的内容
}

第二种方法:
用一个线程来实现这种方法,

#4


while(1)
{
sleep(1);///睡1秒,linux下。
}

#5


2楼说的很详细了。

#6


如果不要求很精确的话,用 alarm() 和 signal() 就够了
代码:
/*
 * Example for alarm.
 */
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void sigalrm_fn(int sig)
{
        /* Do something */
        printf("alarm!\n");
        alarm(2);
        return;
}
int main(void)
{
        signal(SIGALRM, sigalrm_fn);
        alarm(2);
        /* Do someting */
        while(1) pause();
}

#7


#8


sleep() alarm() 是精确到秒的,setitimer(),select()是精确到微妙的

#9


ls的挖坟呀

#10


一天之后的话用crontab命令

#11


libevent