Linux下定时器的使用

Linux下应用层定时器原本有好几种,大伙能够去搜索其余帖子博客,这里我主要描述我在使用setitimer时候遇到的问题,话很少说,直接上代码吧
linux

例子一:只有定时器任务,为模拟复杂,我特地加个锁操做

// lock_timmer_test.cpp
ios

#include <iostream>
#include <sys/time.h>
#include <signal.h>
#include <linux/types.h>
#include <sched.h>
#include <pthread.h> 
using namespace std;

//互斥锁
class MutexLock
{
public:
    MutexLock(){ pthread_mutex_init(&m_stMutex, NULL); }
    ~MutexLock(){ pthread_mutex_destroy(&m_stMutex); }

    void lock(){  pthread_mutex_lock(&m_stMutex);}
    int unlock() {return pthread_mutex_unlock(&m_stMutex); }

    bool trylock(){ return pthread_mutex_trylock(&m_stMutex) == 0;}
    pthread_mutex_t* getMutexPtr(){ return &m_stMutex;}
private:
    pthread_mutex_t m_stMutex;
};


MutexLock test_mutex;
int timestep = 1;  //定时器的时间间隔

//五秒切换插入map顺序
void timeout_cb(int sig)
{
    test_mutex.lock();
    std::cout<<"  timer lock : "<<std::endl;
    test_mutex.unlock();
}


//开启定时器
void set_timer() 
{   
    struct sigaction sigact;
    sigact.sa_flags =  0;
    sigact.sa_handler = timeout_cb; // 设置定时器的回调函数
    sigemptyset(&sigact.sa_mask);
    sigaction(SIGALRM, &sigact, NULL);

    // //结构成员it_value指定首次定时的时间,
    // // 结构成员it_interval指定下次定时的时间
    // // 定时器工做时,先将it_value的时间值减到0,
    // // 发送一个信号,再将it_value赋值为it_interval的值,从新开始定时,如此反复。
    struct itimerval itv;
    itv.it_interval.tv_sec = timestep;
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec = timestep;
    itv.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL, &itv, NULL);
}


int main(int argc, char const *argv[])
{
    set_timer();
    while(true)
    {
        // test_mutex.lock();
        // std::cout<<"               main lock"<<std::endl;
        // test_mutex.unlock();
    }

    return 0;
}

编译:g++ lock_timmer_test.cpp      运行: ./a.out函数

运行结果证实:的确每隔timestep,回调函数就会被调用,执行特定任务学习


举例二:问题引伸一下,咱们把上述代码中main函数中的注释去掉,这时候会发生奇怪现象,整个程序会在回调调用的以后死锁,如图所示:

    回调函数作的操做复杂后,可能因为调度问题或者是我本身代码没写好仍是其余缘由,在本例中,会出现死锁问题,查了相应的资料,有人建议回调函数不要太复杂,可能因为CPU调度问题和定时事件过短的而形成不肯定因素。
ui

    因此在使用setitimer()的时候,咱们尽可能不要让回调函数作过于复杂的操做,最好只是作某些标志位的置位操做就好。spa

详情参见例四。
线程

举例三:使用setitimer()定时器的时候,貌似不支持多个定时器的设置,详情看代码及运行结果,具体缘由是什么,还请各位知道的指教指教。

#include <iostream>
#include <sys/time.h>
#include <signal.h>
#include <linux/types.h>
#include <sched.h>
#include <pthread.h> 

using namespace std;

//互斥锁
class MutexLock
{
public:
    MutexLock(){ pthread_mutex_init(&m_stMutex, NULL); }
    ~MutexLock(){ pthread_mutex_destroy(&m_stMutex); }

    void lock(){  pthread_mutex_lock(&m_stMutex);}
    int unlock() {return pthread_mutex_unlock(&m_stMutex); }

    bool trylock(){ return pthread_mutex_trylock(&m_stMutex) == 0;}
    pthread_mutex_t* getMutexPtr(){ return &m_stMutex;}
private:
    pthread_mutex_t m_stMutex;
};


MutexLock test_mutex;
int timestep = 1;

//五秒切换插入map顺序
void timeout_cb(int sig)
{
    test_mutex.lock();
    std::cout<<"  timer lock : "<<std::endl;
    test_mutex.unlock();
}
//五秒切换插入map顺序
void timeout_cb2(int sig)
{
    test_mutex.lock();
    std::cout<<"  timer2 lock : "<<std::endl;
    test_mutex.unlock();
}

void set_timer() 
{   
    struct sigaction sigact;
    sigact.sa_flags =  0;
    sigact.sa_handler = timeout_cb; //定时器回调函数
    sigemptyset(&sigact.sa_mask);
    sigaction(SIGALRM, &sigact, NULL);

    // //结构成员it_value指定首次定时的时间,
    // // 结构成员it_interval指定下次定时的时间
    // // 定时器工做时,先将it_value的时间值减到0,
    // // 发送一个信号,再将it_value赋值为it_interval的值,从新开始定时,如此反复。
    struct itimerval itv;
    itv.it_interval.tv_sec = 2*timestep;
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec = 2*timestep;
    itv.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL, &itv, NULL);
}
//设置uuid五秒切换插入顺序的定时器
void set_timer2() 
{   
    struct sigaction sigact;
    sigact.sa_flags =  0;
    sigact.sa_handler = timeout_cb2; 
    sigemptyset(&sigact.sa_mask);
    sigaction(SIGALRM, &sigact, NULL);

    // //结构成员it_value指定首次定时的时间,
    // // 结构成员it_interval指定下次定时的时间
    // // 定时器工做时,先将it_value的时间值减到0,
    // // 发送一个信号,再将it_value赋值为it_interval的值,从新开始定时,如此反复。
    struct itimerval itv;
    itv.it_interval.tv_sec = timestep;
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec = timestep;
    itv.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL, &itv, NULL);
}
int main(int argc, char const *argv[])
{
    set_timer();
    set_timer2();
    while(true)
    {
        // test_mutex.lock();
        // std::cout<<"               main lock"<<std::endl;
        // test_mutex.unlock();
    }

    return 0;
}

运行结果:code

  从运行结果中能够看出,只有第二个定时器在运行,第一个被覆盖了,这对于咱们想要同时设置两种定时器的需求,貌似得不到解决(知识点的局限,应该是咱们代码有问题,还请大牛解答)。事件

    因此针对须要设置多个定时器,我最后推荐使用select,或者使用libevent库中的定时器,具体参见例五,libevent的Timmer。get

举例四:定时器回调函数只作标志位置位操做,另开一个线程,根据标志位作相应的操做。

#include <iostream>
#include <sys/time.h>
#include <signal.h>
#include <linux/types.h>
#include <sched.h>
#include <pthread.h> 

using namespace std;

//互斥锁
class MutexLock
{
public:
    MutexLock(){ pthread_mutex_init(&m_stMutex, NULL); }
    ~MutexLock(){ pthread_mutex_destroy(&m_stMutex); }

    void lock(){  pthread_mutex_lock(&m_stMutex);}
    int unlock() {return pthread_mutex_unlock(&m_stMutex); }

    bool trylock(){ return pthread_mutex_trylock(&m_stMutex) == 0;}
    pthread_mutex_t* getMutexPtr(){ return &m_stMutex;}
private:
    pthread_mutex_t m_stMutex;
};


MutexLock test_mutex;
int timestep = 1;
bool time_is_now = false;


//五秒切换插入map顺序
void timeout_cb(int sig)
{
   time_is_now = !time_is_now;
}


void set_timer() 
{   
    struct sigaction sigact;
    sigact.sa_flags =  0;
    sigact.sa_handler = timeout_cb; //定时器回调函数
    sigemptyset(&sigact.sa_mask);
    sigaction(SIGALRM, &sigact, NULL);

    // //结构成员it_value指定首次定时的时间,
    // // 结构成员it_interval指定下次定时的时间
    // // 定时器工做时,先将it_value的时间值减到0,
    // // 发送一个信号,再将it_value赋值为it_interval的值,从新开始定时,如此反复。
    struct itimerval itv;
    itv.it_interval.tv_sec = 2*timestep;
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec = 2*timestep;
    itv.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL, &itv, NULL);
}


void* lokc_unlock(void * arg)
{
    while(true)
    {
        if(time_is_now)
        {
            test_mutex.lock();
            std::cout<<"  timer lock : "<<std::endl;
            test_mutex.unlock();
            time_is_now = false;// 置位
        }
    }
   
}


int main(int argc, char const *argv[])
{
    set_timer();

    pthread_t autorecv_child_thread;

    int res;
    if((res=pthread_create(&autorecv_child_thread,NULL,lokc_unlock, NULL))!=0)
    {
        std::cout<<"111111111111111"<<std::endl;
        return -1;
    }

    if( (res = pthread_detach(autorecv_child_thread) ) != 0 )
    {
        std::cout<<"2222222222222222"<<std::endl;
        return -1;
    }

    while(true)
    {
        usleep(100000);
        test_mutex.lock();
        std::cout<<"               main lock"<<std::endl;
        test_mutex.unlock();
    }

    return 0;
}

运行结果:

    从运行结果中能够看出: 定时器回调函数只作简单任务,复杂任务交由子线程处理,这样不会出什么问题。


举例五:使用libevent的Timmer(即select模式使用定时任务)

    当须要多个定时任务同时定时操做的时候,由于本人暂时尚未找到setitimer的正确用法,所以不得不借用libevent的Timmer来实现,固然直接用select也能够,能够去搜索相应资料学习。

#include <iostream>
#include <sys/time.h>
#include <signal.h>
#include <linux/types.h>
#include <sched.h>
#include <pthread.h> 
#include <event2/event.h>
#include <event2/thread.h>
#include <event2/event-config.h>
using namespace std;

//互斥锁
class MutexLock
{
public:
    MutexLock(){ pthread_mutex_init(&m_stMutex, NULL); }
    ~MutexLock(){ pthread_mutex_destroy(&m_stMutex); }

    void lock(){  pthread_mutex_lock(&m_stMutex);}
    int unlock() {return pthread_mutex_unlock(&m_stMutex); }

    bool trylock(){ return pthread_mutex_trylock(&m_stMutex) == 0;}
    pthread_mutex_t* getMutexPtr(){ return &m_stMutex;}
private:
    pthread_mutex_t m_stMutex;
};

MutexLock test_mutex;
int timestep = 1;

//五秒切换插入map顺序
void timeout_cb(int fd, short event, void *params)
{
    test_mutex.lock();
    std::cout<<"   timmer1  lock"<<std::endl;
    test_mutex.unlock();
}

void timeout_cb2(int fd, short event, void *params)
{
    test_mutex.lock();
    std::cout<<"                  timmer2  lock"<<std::endl;
    test_mutex.unlock();
}


void* lokc_unlock(void * arg)
{
    event_base* base = event_base_new(); 

    struct event *timeout = NULL;
    struct timeval tv = {timestep, 0};
    timeout = event_new(base, -1, EV_PERSIST, timeout_cb, NULL);
    evtimer_add(timeout, &tv);

    struct event *timeout2 = NULL;
    struct timeval tv2 = {2*timestep, 0};
    timeout2 = event_new(base, -1, EV_PERSIST, timeout_cb2, NULL);
    evtimer_add(timeout2, &tv2);

    event_base_dispatch(base); 
    event_base_free(base);
}


int main(int argc, char const *argv[])
{
    pthread_t autorecv_child_thread;

    int res;
    if((res=pthread_create(&autorecv_child_thread,NULL,lokc_unlock, NULL))!=0)
    {
        std::cout<<"111111111111111"<<std::endl;
        return -1;
    }

    if( (res = pthread_detach(autorecv_child_thread) ) != 0 )
    {
        std::cout<<"2222222222222222"<<std::endl;
        return -1;
    }

    while(true)
    {
       
    }

    return 0;
}


运行结果:

从最后结果中看,本人仍是比较推荐使用libevent这种库,毕竟使用简单,功能强大。

ps:固然对于setitimer()来讲,它支持延迟开启定时器,即itimerval 的 it_intercal 和it_value的含义,libevent对于相应的支持就须要各位本身动脑筋想办法了。(欢迎各位指教)

相关文章
相关标签/搜索