fork产生僵死子进程的问题

之前写的一个程序,调用fork产生子进程,子进程进行实际工作,父进程则使用信号处理函数来接收子进程结束信号,然后调用waitpid,处理子进程的僵死进程。

按理说这样做,应该不会出现僵死进程了,但是,经过大量实际数据测试后,还是会出现僵死进程。

一直都找不到问题原因,最后使用ps命令得到父进程的pid,并用gdb调试器attach父进程,执行bt命令,发现堆栈情况如下

(gdb) bt

#0  0x000000355b30aecb in __lll_mutex_lock_wait () from /lib64/tls/libpthread.so.0

#1  0x 0000000000483c 26 in baselib::Simple_Log::print (this=0x 2a 9633fce8, format=0x 2a 96332c 00 "") at simple_log.cpp:414

#2  0x0000000000484d 82 in baselib::Simple_Log::LOCK (this=0x1ffc790) at ../inc/base/simple_log.h:231

#3  0x 0000000000483c 4e in baselib::Simple_Log::print (this=0x1ffc790, format=0x4925b0 "[%s](%d) %s FILE:[%s],LINE:[%d]%s")

    at simple_log.cpp:418

#4  0x 00000000004071c 0 in baselib::LogInstance_Ex::operator() (this=0x7fbfffc520,

    fmt=0x492550 "[sig_child] child process pid=%d exited") at ../inc/base/baselog.h:213

#5  0x 0000000000405c 79 in sig_child () at Worker.cpp:23

#6  <signal handler called>

#7  0x 000000355a 880546 in __offtime () from /lib64/tls/libc.so.6

#8  0x 000000355a 88275d in __tz_convert () from /lib64/tls/libc.so.6

#9  0x000000000048e2cd in _localtime64_r (now=0x0, _t=0x7fbfffcb48, p=0x7fbfffcb90) at date2038.cpp:279

#10 0x000000000048e 3f 5 in base_localtime64_r (_t=0x7fbfffcd68, p=0x7fbfffcb90) at date2038.cpp:311

#11 0x 0000000000474485 in baselib::Date::GetLocalTm (this=0x7fbfffcd60, ptm=0x7fbfffcb90) at date.cpp:297

#12 0x 0000000000475f 2b in baselib::Date::GetMonth (this=0x7fbfffcd60) at date.cpp:822

#13 0x000000000048324d in baselib::Simple_Log_Policy::RollOver (this=0x1ffcbe8) at simple_log.cpp:179

#14 0x0000000000484bbb in baselib::Simple_Log::RollOver (this=0x1ffc790) at simple_log.cpp:790

#15 0x 0000000000483c 79 in baselib::Simple_Log::print (this=0x1ffc790, format=0x4925b0 "[%s](%d) %s FILE:[%s],LINE:[%d]%s")

    at simple_log.cpp:427

#16 0x 00000000004071c 0 in baselib::LogInstance_Ex::operator() (this=0x7fbfffe100,

    fmt=0x492808 "[CWorker::MainProcess] child process pid=%d exited") at ../inc/base/baselog.h:213

#17 0x 0000000000406c 25 in CWorker::MainProcess (this=0x5d1620) at Worker.cpp:189

#18 0x000000000042744e in CBaseApp::Run (this=0x5d1620) at ../../frame/baseframe/BaseApp.cpp:231

#19 0x 000000000042a 7eb in main (argc=5, argv=0x7fbffff7b8) at ../../frame/baseframe/BaseFrameMain.cpp:29

 

首先发现,顶层堆栈是__lll_mutex_lock_wait(),说明发生了死锁,而程序中只有在写日志时用到了锁。接下来的几层堆栈说明确实是在写日志时发生了死锁。

再往下看,发现有如下一层

#6  <signal handler called>

这说明有信号发生了,即收到了子进程结束的信号。再看该层下面的堆栈,这下找到原因了,原来是父进程需要维护子进程的数量,在信号处理函数中将子进程的数量减一,并且写一个日志,记录某某子进程已经退出。

这样,在父进程写日志时,使用Simple_Log::LOCK()对日志文件上锁完成,但还没有解锁之前,此时可能有子进程结束信号发生了,这时父进程中断正在写日志的操作,而转去执行信号处理函数,在信号处理函数中,再次调用Simple_Log::LOCK()对同一个日志文件锁上锁,由于该锁之前已经上锁,还未解锁,再次上锁会造成死锁。当其它子进程结束后,向父进程发送的子进程结束信号得不到处理,所以就会处在僵死状态。

找到原因后,修改父进程的信号处理函数,将写日志的操作去掉,再次执行,已没有出现僵死进程的现象,问题解决。

 

总结,当初在写该信号处理函数之前,本不想写日志操作的,因为觉得信号处理函数是中断正在执行的业务操作而去执行其它操作,如果太过复杂,执行时间较长的话,会影响正在执行的业务处理。但是,为了提高日志信息的可维护性,最后还是写了日志,没有考虑到这种错误情况会发生。现在想来,中断处理函数还是应该遵循以下几个原则为好

1、越简单越好

2、能越早返回越好

3、如果在中断处理函数中需要上锁,这种情况要特别注意

4、不要调用太多的其它函数,有可能这些函数也会阻塞

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值