多线程下的多定时器处理

时间:2021-11-02 23:18:36

原文地址:http://hi.baidu.com/sunwater007/item/aa179939f7a491c7392ffa91

问题的提出:多线程中每个线程都需要一个单独的定时器,而且其他线程并不知道该线程中的定时器的存在,由于普通的unix处理定时器的信号方式是一个进程下只能有一个定时器起作用。如果设置多个定时器可能被后续的定时器洗刷掉。那么如何让多个线程独立的使用不同的信号而不被洗刷掉呢? 


问题的解决:由于目前的posix里面定义了SIGMIN~SIGMAX信号供用户自定义以扩展程序,那么最好采用此类信号,而不是用32之前的信号; 
同时使用sigaction代替signal函数,避免信号丢失的问题; 
定时器采用posix TMR方案,不能使用普通的itimer结构。 
综上所述,实现的代码如下: 
/***********************************************************/ 
/* 
* Because some platforms define different names for signals between SIGMIN and SIGMAX or other 
* similar ones. you may use "kill -l" to get these self-defined signals in your platform. 

* Compile:gcc -lrt -lpthread test.c -o test 
* Run:     ./test 

* By kinghuang, gdnt rnd. 
* sunwater007@gmail.com 
*/ 
#include   <stdio.h> 
#include   <time.h> 
#include   <signal.h> 
void timer1_handler(int signo) 

    static int index = 0; 
     
    printf("timer1_handler captures signal: %d, index: %d\n", signo, index++); 

void timer2_handler(int signo) 

    static int index = 0; 

    printf("timer2_handler, sig: %d, index: %d\n", signo, index++); 

void set_timer1() 

    struct sigaction     sig_act; 
    struct sigevent      sig_event; 
    sigset_t                sig_set; 
    struct itimerspec   timer_setting; 
    timer_t                 timer_id; 
     
    // set sigaction. 
    sigemptyset(&sig_act.sa_mask); 
    sig_act.sa_flags = 0; 
    sig_act.sa_handler = timer1_handler; 
    if ( sigaction(SIGRTMIN + 2, &sig_act, NULL) < 0) 
    {   printf(" timer1 sigaction meets problem.\n"); return; } 
     
     
    sig_event.sigev_notify = SIGEV_SIGNAL; 
    sig_event.sigev_signo = SIGRTMIN + 2; 
    if ( timer_create(CLOCK_REALTIME, &sig_event, &timer_id) < 0) 
    {   printf("create timer1 failed.\n"); return; } 
     
    timer_setting.it_value.tv_sec = 1; 
    timer_setting.it_value.tv_nsec = 0; 
    timer_setting.it_interval.tv_sec = 1; 
    timer_setting.it_interval.tv_nsec = 0; 
    if ( timer_settime(timer_id, 0, &timer_setting, NULL) < 0) 
    {   printf("set timer failed. \n"); return; } 
     
    sigemptyset(&sig_set); 
    while ( 1) 
    {   sigsuspend(&sig_set); } 

void set_timer2() 

    struct sigaction     sig_act; 
    struct sigevent      sig_event; 
    sigset_t                sig_set; 
    struct itimerspec   timer_setting; 
    timer_t                timer_id; 
     
    // set sigaction. 
    sigemptyset(&sig_act.sa_mask); 
    sig_act.sa_flags = 0; 
    sig_act.sa_handler = timer2_handler; 
    if ( sigaction(SIGRTMAX - 1, &sig_act, NULL) < 0) 
    {   printf(" timer1 sigaction meets problem.\n"); return; } 
     
    // set signal event for the timer timeout. 
    sig_event.sigev_notify = SIGEV_SIGNAL; 
    sig_event.sigev_signo = SIGRTMAX - 1; 
    if ( timer_create(CLOCK_REALTIME, &sig_event, &timer_id) < 0) 
    {   printf("create timer1 failed.\n"); return; } 
     
    // timer setting. The setting can be used by more than one timer. 
    timer_setting.it_value.tv_sec = 1; 
    timer_setting.it_value.tv_nsec = 0; 
    timer_setting.it_interval.tv_sec = 1; 
    timer_setting.it_interval.tv_nsec = 0; 
    if ( timer_settime(timer_id, 0, &timer_setting, NULL) < 0) 
    {   printf("set timer failed. \n"); return; } 
     
    sigemptyset(&sig_set); 
    // wait for timer timeout. 
    while ( 1) 
    {   sigsuspend(&sig_set); } 

int main() 

    pthread_t t1, t2; 
     
    pthread_create(&t1, NULL, (void *)set_timer1, NULL); 
    pthread_create(&t2, NULL, (void *)set_timer2, NULL); 
    pthread_join(t2, NULL); 

    return 0; 

/************************************************************/ 
run result: 
king>./test 
timer2_handler, sig: 63, index: 0 
timer1_handler captures signal: 36, index: 0 
timer2_handler, sig: 63, index: 1 
timer1_handler captures signal: 36, index: 1 
timer2_handler, sig: 63, index: 2 
timer1_handler captures signal: 36, index: 2 
timer2_handler, sig: 63, index: 3 
timer1_handler captures signal: 36, index: 3