问题描述:在main中加入了捕捉【硬件错误引起的SIGBUS等信号】的代码,然后图片无法传输了。
解决问题步骤描述:
通过 数次的注释信号安装sigaction,发现问题是由该代码引起。用fprintf打印函数执行情况,发现卡在了loadimge,的log_DEBUG中,于是gdb打印线程栈
嗯,果然死锁了,但是为什么卡的锁不一样,但所有线程都锁了呢?于是先注释掉了【开线程写回日志,开线程计算特征向量,开线程写回socket】。再次打印线程栈。
蒙逼了···主线程阻塞在epoll_wait、检测读队列分配读任务的线程由于任务队列空而sleep了、只有读图片的那个程序阻塞了。可为什么一个线程会阻塞在一个锁上面呢!!!!!太奇怪了。我不信,于是在MUTEX中,加了打印锁地址和加锁,解锁的信息。
第916539568号锁,用于锁住读队列检测队列是否为空的锁,使用正常。而第916539856号锁,用于锁住LOG对象,用以对文本输出的锁,在锁住之后就特么没解开过。在获取mutex后的字符串,没有打印···
于是定位 volatile MUTEX g(&mu);这一句有问题,想起了那个被编译器优化调戏的上午,我决定将volatile注释掉,在makefile中关掉-O2编译器优化。
是的,狗日的正常了,一切正常了。
仍待解决的问题:为什么volatile、sigaction、-O2编译器优化凑合在一起会出问题呢?
用pthread_sigmask在【除特定线程外】所有线程中阻塞所有信号。测试结果kill -9即第一类信号,果然无法阻塞,kill -9 pid立即杀死服务器进程;在serv_read线程中添加f/=0,即在特定线程产生SIGFPE信号,果然专门用于等待信号的那个线程,没能接收到SIGFPE,即第二类信号只会在局限于发生硬件错误的那个线程。对于第三类信号,也就是异步信号,这里在所有线程【除专门处理信号的那个线程外】用pthread_sigmask阻塞所有信号。在专门处理信号的那个线程中用sigwait来等待信号。
关于第二类信号,也即同步信号,如SIGSEGV、SIGFPE、SIGILL、SIGBUS,用singal安装信号处理函数。在信号处理函数中用pthread_exit,杀死自己,这样这个线程的崩溃不会影响其他线程。另外singal和sigaction的区别:singal只安装信号处理函数一次,下次要用需要自己在信号处理函数中安装,但是由于信号处理函数开始和再次singal信号之间不是原子操作,所以如果在这个间隙又有了同类信号,那么信号就会丢失。所以还是使用sigaction来的好,sigaction在处理信号的时候会设置信号屏蔽字,将信号阻塞起来,这样一个信号都不会丢了。测试结果:在信号处理函数中调用pthread_exit使得出现浮点错误的线程自杀,这样就不会妨碍到其他线程运行了(默认操作是kill掉整个进程)。ps -Lf pid 查看kill前后的进程pid的线程数,发现线程数没有发生变化,表明出错线程自杀成功且未影响到其他线程。遗憾的是信号处理函数不能传自定义参数,这样就无法将tcp套接字发送进去,如果能在线程退出前,将套接字关掉就更好了。现在只能在客户端发送完数据之后将套接字关掉,但这样存在的问题是原套接字中的内容怎么办?会不会影响到下次使用这个套接字?
果然,测试了4次,4个CLOSE_WAIT。这该怎么办?只能将调度队列做成全局了吗?
哈哈哈,可以将服务器端的套接字设置成keepalive。默认测试时间为2h,对端发回RST,则本端关闭套接字。