一个老系统的问题,用的system v消息队列同步等响应,经过alarm信号来进行超时控制。如今系统进行升级改造(所谓云化),原来进程处理的逻辑所有改为了线程框架,问题就出现了。alarm信号发出的时候,到底哪一个线程会接收到这个信号呢?linux
因而赶紧问了下百度,有些地方说随机的,有些地方解答说随机的;另外有些人推荐用pthread_sigmask和sgwait之类,云者颇多。还有些同仁推荐改用异步消息队列,在没有消息的时候进行usleep、nanosleep,posix消息队列等等。安全
最后用了usleep,之因此不用另外的,我一个一个说个大概:框架
pthread_sigmask,这个方式试了下,咱们提供的是客户端,也就是给别人的lib。这些依赖于调用进程主动作一些事情,出了问题排查比较难。试了一段时间发现,对宿主进程的改造比较多,定位也没玩没了,由于别人也是一个经历了十几年没有重构的老系统了。异步
posix消息队列,这个是支持异步的。可是整个团队都是延续着system v的使用习惯,在核心流程里面直接改为posix会影响维护的压力函数
消息队列nowait,而后usleep。网上不少文章说usleep有着这样那样的问题(不许确,线程不安全,影响信号一堆啥的)post
因此我还测试了下(代码就不贴了,比较多),以下: OS版本Linux 2.6.32-358.el6.x86_64测试
function time(usec) realTime reduce
-------------------------------------------------------------------
usleep 500000 500138 138
nanosleep 500000 500139 139
select 500000 500591 591
usleep 100000 100133 133
nanosleep 100000 100129 129
select 100000 100147 147
usleep 50000 50132 132
nanosleep 50000 50128 128
select 50000 50130 130
usleep 10000 10130 130
nanosleep 10000 10107 107
select 10000 10129 129
usleep 1000 1077 77
nanosleep 1000 1064 64
select 1000 1079 79
usleep 900 971 71
nanosleep 900 973 73
select 900 971 71
usleep 500 570 70
nanosleep 500 563 63
select 500 571 71
usleep 100 168 68
nanosleep 100 168 68
select 100 158 58
usleep 10 68 58
nanosleep 10 67 57
select 10 67 57
usleep 1 60 59
nanosleep 1 57 56
select 1 58 57线程
结果显示,usleep500网上,基本偏差仍是很小的,往下的话就很不精确了。队列
扯了这多和主题无关的,这里是分割线=============================================进程
上面也提到了,我中间经历了使用pthread_sigmask,可是有问题,基于对线程信号的陌生。我写了一个测试程序看看,代码以下:
#include <pthread.h> #define TH_NUM 10 volatile int signflag = 0; void sigalarm(int sign) void sigmaskhandleset(int sign, void (*handle)(int)) memset(&new_sigaction, 0x00, sizeof(new_sigaction)); sigemptyset(&new_sigaction.sa_mask); sigaction(sign, &new_sigaction, &old_sigaction);
sigmaskhandleset(SIGALRM, sigalarm); // usleep(1000000); printf("thread_proc_1's signflag : %d , pid : %ld\n", signflag, pid); void* thread_proc_2(void* pMgr) sigmaskhandleset(SIGALRM, sigalarm); // usleep(1000); printf("thread_proc_2's signflag : %d , pid : %ld\n", signflag, pid); void* thread_alarm_post(void* pMgr) int main() sigset_t set; pthread_attr_init(&pthread_attr); ret = pthread_create(&t_id[1], &pthread_attr, thread_proc_2, NULL); printf("main() my self thread_id : %ld\n", pthread_self()); ret = pthread_create(&t_id[2], &pthread_attr, thread_alarm_post, NULL);
|
各类状况都测试了下,里面的注释掉那部分其实也是测试过程当中的一部分。总结了下(基于测试的OS版本,不针对其它OS):
一、使用过程当中看不出来usleep、sleep会产生SGIALRM信号(针对网上说的usleep会影响信号这一方面验证的)
二、过程当中看不出来usleep、sleep会影响线程之间的安全(针对网上说的usleep线程不安全)
三、信号先被哪一个线程接收?我仍是没法肯定,也有多是随机的。
可是能够肯定的是linux下确定不是最后一个注册信号处理函数的那个线程
我以为也不是正在运行的那个线程,道理很简单,由于若是主线程不屏蔽信号,那么一直都是主线程处理信号
不然的话,一直都是第一个线程先处理
四、我测试了几百遍一样一个程序(没有改代码重编的状况下),都是pthread_self()最大的那个线程处理了信号响应。这能说明什么问题吗?
我不能这么下结论,可是他应该说明了些什么东西!
今天又讨论起来这个问题,从新作了一次测试!补充一些上次疏漏的地方:
一、测试结果仍是结果仍是最大的线程接收,也就是说若是主线程没有屏蔽!那么处理信号中断函数的pthread_self()函数返回的都是主线程的id
二、可是每次中断不肯定是主线程,而有多是其它子线程!
三、线程在sleep过程当中,每次被中断以后并非马上返回!而是不可预测的中断次数以后返回了
四、pthread_kill函数每次都会及时中断,并且这个过程当中sleep会里面返回