信号处理函数误用不可重入函数导致的进程死锁情况

记一次进程死锁的情况:

某天突然发现进程不再运行处理且有没有崩溃产生core文件;

使用gdb -p pid查看堆栈信息如下:

 1 #0  0x000000376faf83ae in __lll_lock_wait_private () from /lib64/libc.so.6
 2 #1  0x000000376fa7d35b in _L_lock_10288 () from /lib64/libc.so.6
 3 #2  0x000000376fa7ab83 in malloc () from /lib64/libc.so.6
 4 #3  0x000000376fa80f42 in strdup () from /lib64/libc.so.6
 5 #4  0x000000376fa9d9c1 in tzset_internal () from /lib64/libc.so.6
 6 #5  0x000000376fa9db39 in __tz_convert () from /lib64/libc.so.6
 7 #6  0x000000376fa9bc59 in ctime () from /lib64/libc.so.6
 8 #7  0x0000000000405017 in AdAnalizeBayu::sigHandle (sig=14) at AdAnalizeBayu.cpp:56
 9 #8  <signal handler called>
10 #9  0x000000376fa79ade in _int_malloc () from /lib64/libc.so.6
11 #10 0x000000376fa7a7ed in calloc () from /lib64/libc.so.6
12 #11 0x000000000042aaeb in operator new (size=48) at memcheck.cpp:302
13 #12 0x000000000041c3cf in __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<std::string const, std::string> > >::allocate (
14     this=0x7ffca027e950, __n=1) at /usr/include/c++/4.8.2/ext/new_allocator.h:104
15 #13 0x000000000041c2b8 in std::_Rb_tree<std::string, std::pair<std::string const, std::string>, std::_Select1st<std::pair<std::string const, std::string> >, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::_M_get_node (this=0x7ffca027e950)
16     at /usr/include/c++/4.8.2/bits/stl_tree.h:370
17 #14 0x000000000041c1bf in std::_Rb_tree<std::string, std::pair<std::string const, std::string>, std::_Select1st<std::pair<std::string const, std::string> >, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::_M_create_node (this=0x7ffca027e950, 
18     __x=...) at /usr/include/c++/4.8.2/bits/stl_tree.h:380
19 #15 0x000000000041beb4 in std::_Rb_tree<std::string, std::pair<std::string const, std::string>, std::_Select1st<std::pair<std::string const, std::string> >, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::_M_insert_ (this=0x7ffca027e950, 
20     __x=0x0, __p=0x27bfa00, __v=...) at /usr/include/c++/4.8.2/bits/stl_tree.h:1023
21 #16 0x000000000041b8b0 in std::_Rb_tree<std::string, std::pair<std::string const, std::string>, std::_Select1st<std::pair<std::string const, std::string> >, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::_M_insert_unique_ (
22     this=0x7ffca027e950, __position=..., __v=...) at /usr/include/c++/4.8.2/bits/stl_tree.h:1482
23 #17 0x000000000041b6a2 in std::map<std::string, std::string, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::insert (this=0x7ffca027e950, __position=..., __x=...) at /usr/include/c++/4.8.2/bits/stl_map.h:648
24 #18 0x000000000041b48f in std::map<std::string, std::string, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::operator[] (this=0x7ffca027e950, __k=...) at /usr/include/c++/4.8.2/bits/stl_map.h:469
25 #19 0x0000000000441ada in kfc::CCgiPara::Decode () at kfc_parsepara.cpp:147
26 #20 0x000000000042248b in CUdpServer::OnDoProcess () at udp_server.cpp:76
27 #21 0x00000000004240d5 in CUServer::ReadFromSvrPort (this=0x6622a0 <CUdpServer::getInstance()::srv>) at userver.cpp:97
28 #22 0x000000000042427f in CUServer::Run (this=0x6622a0 <CUdpServer::getInstance()::srv>) at userver.cpp:121
29 #23 0x000000000041aaf6 in main (argc=2, argv=0x7ffca027ff78) at main.cpp:62

由堆栈编号11可以看到程序在往std容器map内插入一个红黑树节点调用了系统调用_int_malloc()函数申请一片空间的时候,定时器信号过来,进程进入了信号处理函数(堆栈编号8)。

此时这片内存空间是有被加上锁的;

在信号处理函数内调用了库函数ctime(),这个函数后来查阅资料得知是不可重入函数(即会导致结果不可预知)。在该函数内调用了malloc函数会对同一批空间加锁,由于这篇内存空间已被之前加过锁导致进程在此处阻塞。进程在信号处理函数内阻塞等待std容器添加完后释放锁,std容器添加过程又在等待信号处理函数处理完毕后释放锁。导致进程进入死锁状态。

解决办法:

ctime函数在我的信号处理函数内不是必须存在的,因此做了删减另外实现。死锁情况解决。

总结:

在信号处理函数内一定不要使用不可重入函数。虽然posix标准规定标准库函数必须都是可重入函数,但仍有少数是不可重入函数:

 

 

 

 

 

posted @ 2019-12-12 12:34  只取一瓢饮  阅读(1019)  评论(0编辑  收藏  举报