前阵子写代码遇到多线程下usleep会卡死的情况。
看日志是线程卡死,于是gdb进去看,但是没有发现死锁,还是正常的停留在usleep中了,最后才发现是usleep进去后出不来了。
周末做了个实验,发现似乎跟机器有关,另外一台机器就一直没有出现这种情况。
还发现了一个情况,就是虽然usleep会卡死,但是过大概50分钟,就会从usleep中退出来。并没有出现永远卡死的情况。每次出现都是卡住50分钟后恢复,但是我的程序里面也没有50分钟的定时器。
发现有2个线程可能会卡死,都是循环中usleep(1000)的。
尝试把试着把usleep的返回值打印出来,发现是否卡死后退出,都没有返回失败。也没有任何一个usleep返回过失败。
并不所有的机器都会出现,很莫名其妙。以前线上也从来没有出现过这类问题。
很奇怪,于是群发邮件给同事,有人说make clean一把,有人不相信usleep会退步出来。
“把出问题那台机器的目标文件全部删掉,重新make一下试试;”
-------------------------
出问题的机器没有编译代码,只是把编译后的程序放上去了。2台机器运行的都是同样的执行程序。操作系统也同样。
“遇到过,但现象不一样,是卡死之后不会出来。
问题在于/usr/include/bits/typesizes.h中定义的__FD_SETSIZE和进程中定义的不一致。”
-----------------------
看了下2个系统的__FD_SETSIZE都一样,进程里面也没有重新定义__FD_SETSIZE
“这上面说是与SIGALRM信号处理有关。按理说linux里每个线程 都有进程号,usleep发的信号应该是发到线程的进程号上。但如果是发到进程组,可能会有问题,因为信号不会积累。
做个测试就可以确认了,写个信号捕捉函数,放到主进程,等抓到SIGALRM 后,如果应该是线程的,那就可能出问题。”
--------------------
于是我写了个简单的程序。
发现捕获不了usleep里面的alarm的信号
void sigAlarmhandler(int sig)
{
printf("\n alarm \n ");
} int main()
{
signal(SIGALRM, sigAlarmhandler);
while(1)
{
usleep(1);
}