问题背景:工作中遇到一个多线程进程有部分线程(包含主线程)像卡死一样不再处理其他事件,就像无限期休眠了一样
知识点:进程、线程、线程锁、条件变量、socket
定位工具:strace、htop、gdb
问题分析:
由于进程还在,用htop查看进程的线程也都在,首先就是想看看每个线程当前处于什么状态
用gdb工具查看主线程当前堆栈信息如下
可以看到主线程在调用了pthread_join 等待一个线程结束后就阻塞了,具体在等待什么,结合log上下文可以判断出是在等待那个线程(这里根据不同的代码不一样,具体问题具体分析)
接着用gdb工具查看主线程等待要结束的线程的堆栈信息如下
从改线程堆栈信息看该线程停留在pthread_cond_timewait这里,貌似在等待事件或者超时,但一直没有事件,查看超时时间为500ms,可是为什么一直没超时呢?不知道为什么一直没超时
用strace工具跟踪该进程的系统调用和信号传递
第17行 5621是主线程,可以看到他在等待对应线程id 509 退出,第1行 509就是等待要退出的线程,从信息可以看出是在等资源0xd32c2c 等待超时是按系统实时时钟,绝对时间来判断的,2147483611就是要等待的秒数,转换出来就是“2038-01-19 11:13:31”
这是要等到“2038-01-19 11:13:31”才会超时退出,太吓人了,为什么这个超时时间会这么大呢?暂时还不清楚
查看log出问题时的上下文,发现系统时间发生了变化
问题大致猜出来,是由于系统时间被修改为了 1901年,导致的超时时间是未来的 2038年(猜是系统库函数读取不了1970年以前的时间导致,有待研究验证)
解决方案:把线程条件变量的超时时间判断改为用启站的运行时间替换系统实时时钟
注:该问题定位和以上记录大部分都是参数网友已整理的资料,这里把部分重要的参考引用标注如下。另外,根据网友总结用运行时间会多触发系统调用,可能增加cpu使用时间
参考网址:
https://man.linuxde.net/strace
https://blog.csdn.net/Javadino/article/details/2891399
http://man7.org/linux/man-pages/man2/futex.2.html
https://blog.csdn.net/qiuxin315/article/details/8961150
http://www.matools.com/timestamp
https://linux.die.net/man/3/pthread_condattr_setclock
https://www.cnblogs.com/fallenmoon/p/8891218.html
https://www.cnblogs.com/hushaojun/p/7990951.html
https://www.cnblogs.com/raymondshiquan/articles/gettimeofday_vs_clock_gettime.html