原文地址: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