歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

Linux信號處理方法的問題

這周有位新同事請我幫忙看一個關於信號處理的問題,程序希望在收到一個信號後退出,而他在信號處理方法裡卻做了許多事,包括釋放一些全局內存等。

這樣問題就產生了,程序不定時的就掛死了,用gdb一看,所有的線程都掛在了pthread_once方法裡,而似乎每個線程都在處理信號,其中產生問題的線程堆棧如下:

Thread 1 (Thread 0x7f41252f3720 (LWP 31542)):

#0 0x000000339860cb1b in pthread_once () from /lib64/libpthread.so.0

#1 0x00000033982fd6f4 in backtrace () from /lib64/libc.so.6

#2 0x000000339826fa4b in __libc_message () from /lib64/libc.so.6

#3 0x0000003398275366 in malloc_printerr () from /lib64/libc.so.6

#4 0x0000003398278de4 in _int_malloc () from /lib64/libc.so.6

#5 0x0000003398279b91 in malloc () from /lib64/libc.so.6

#6 0x00007f41253b40bd in operator new(unsigned long) () from /usr/lib64/libstdc++.so.6

更多精彩內容:http://www.bianceng.cn/OS/Linux/

#7 0x00007f41253b41d9 in operator new[](unsigned long) () from /usr/lib64/libstdc++.so.6

---Type <return> to continue, or q <return> to quit---

#8 0x000000000045f86a in log4cpp::StringUtil::vform(char const*, __va_list_tag*) ()

#9 0x000000000044eb69 in log4cpp::Category::_logUnconditionally(int, char const*, __va_list_tag*) ()

#10 0x000000000044f4af in log4cpp::Category::warn(char const*, ...) ()

#11 0x00000000004431a1 in singalHandler(int) ()

#12 <signal handler called>

#13 0x000000339860cb19 in pthread_once () from /lib64/libpthread.so.0

#14 0x00000033982fd6f4 in backtrace () from /lib64/libc.so.6

#15 0x000000339826fa4b in __libc_message () from /lib64/libc.so.6

#16 0x0000003398275366 in malloc_printerr () from /lib64/libc.so.6

#17 0x0000003398278de4 in _int_malloc () from /lib64/libc.so

問題在哪裡呢?似乎所有開源代碼裡,都少有人在信號處理方法裡寫大量代碼的,這是為什麼呢?

原因在於,信號是可能在任意時刻打斷你線程的正在執行代碼,信號處理方法插入進去執行時,就可能造成有些函數被反復重入。例如上面這個例子中,thead1正在new一個對象,執行malloc分配內存的過程中,突然被信號打斷,而信號處理方法裡居然又有malloc過程,而malloc是不能反復重入的!於是導致掛死。

另一個問題的,子進程會繼承父進程的很多資源,其中就包括信號,他的程序處理信號後,才pthread_create許多工作線程,而且,沒有屏蔽信號,所以,所有的線程都在處理那個信號處理方法,所有線程都掛死了。

解決方法有很多種,通常是在信號處理方法裡只做少量工作,通知其他線程自我回收資源。

對於多線程程序來說,只弄一個線程使用阻塞式信號處理方法,專職的處理信號,這樣更符合多線程的設計精神。例如,在派生子線程前,用pthread_sigmask來設置信號不會打斷子線程的運行,而在主線程裡,使用阻塞的sigwait方法來同步處理信號,在這裡可以處理一些復雜的操作,不用擔心“重入”問題。

Copyright © Linux教程網 All Rights Reserved