免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2037 | 回复: 9
打印 上一主题 下一主题

[Linux] 僵尸进程的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-01-16 13:19 |只看该作者 |倒序浏览
A进程有B、C两个子进程,B进程先退出,结果B变成僵尸;接着C退出,但是C可以被回收、没有变成僵尸(这时B依然僵死状态)。什么原因会造成这种情况?
A中的SIGCHLD信号处理函数是

  1.     while (1) {
  2.         int status;
  3.         pid_t pid = waitpid(-1, &status, WNOHANG);
  4.         if (pid <= 0) {
  5.             break;
  6.         }
  7.         // something happened with child 'pid', do something about it...
  8.         // Details are in 'status', see waitpid() manpage
  9.     }
复制代码
按照http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=828942的说法,即使B的SIGCHLD丢失,在随后回收C的时候也会把B回收走。
~~~

论坛徽章:
16
CU十二周年纪念徽章
日期:2013-10-24 15:41:3415-16赛季CBA联赛之广东
日期:2015-12-23 21:21:55青铜圣斗士
日期:2015-12-05 10:35:30黄金圣斗士
日期:2015-11-26 20:42:16神斗士
日期:2015-11-19 12:47:50每日论坛发贴之星
日期:2015-11-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-18 06:20:002015亚冠之城南
日期:2015-11-10 19:10:492015亚冠之萨济拖拉机
日期:2015-10-28 18:47:282015亚冠之柏太阳神
日期:2015-08-30 17:21:492015亚冠之山东鲁能
日期:2015-07-07 18:48:39摩羯座
日期:2014-08-29 23:01:42
2 [报告]
发表于 2014-01-16 14:44 |只看该作者
把你整个代码贴出来呢

论坛徽章:
0
3 [报告]
发表于 2014-01-16 15:26 |只看该作者
本帖最后由 sendltd 于 2014-01-16 15:28 编辑

解决了,B的一个线程是D状态,这种情况让进程_exit(1),会导致进程进入Z状态。

论坛徽章:
0
4 [报告]
发表于 2014-01-19 11:36 |只看该作者
回复 3# sendltd
是因为B进程在退出前是D状态吗?

   

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
5 [报告]
发表于 2014-01-26 12:40 |只看该作者
僵尸进程是进程正常退出前的正常状态,B既然已经是Z状态了,为何又是D状态?

论坛徽章:
0
6 [报告]
发表于 2014-01-26 14:10 |只看该作者
回复 4# jasonsungblog

可以这么说,ps的结果是该进程是Z状态,但是用ps H看,它下面的一个线程是D状态。
B在执行exit之前通知某线程dump内核的某些东西,结果这个线程就D在那里了。

   

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
7 [报告]
发表于 2014-01-26 14:41 |只看该作者
sendltd 发表于 2014-01-26 14:10
回复 4# jasonsungblog

可以这么说,ps的结果是该进程是Z状态,但是用ps H看,它下面的一个线程是D状态 ...

这么说就对了,B进程退出时正常进入Z状态,但在真正退出之前需要回收其所有的子线程,需要等所有子线程结束,而因为子线程D挂住,导致B一直处于Z,无法退出。

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
8 [报告]
发表于 2014-02-10 17:39 |只看该作者
回复 7# humjb_1983


    我研究了下内核,看起来这个现象跟内核代码是一致的, 但是很怪异啊

进程B退出的时候调用了do_group_exit, do_group_exit会调用zap_other_threads干掉除主线程外其他的子线程,
zap_other_threads会给子线程发送SIGKILL信号,然后唤醒子线程赶紧处理这个SIGKILL信号并退出,但是处于D状态的线程并没有被唤醒(被signal_wake_up直接忽略了,并不会等待),因此也就没有被干掉。
do_group_exit调完zap_other_threads之后会马上调用do_exit来处理主线程的退出。do_exit会调用exit_notify:
static void exit_notify(struct task_struct *tsk, int group_dead)
{
        bool autoreap;

        if (unlikely(tsk->ptrace)) {
                int sig = thread_group_leader(tsk) &&
                                thread_group_empty(tsk) &&
                                !ptrace_reparented(tsk) ?
                        tsk->exit_signal : SIGCHLD;
                autoreap = do_notify_parent(tsk, sig);
        } else if (thread_group_leader(tsk)) {
                autoreap = thread_group_empty(tsk) &&
                        do_notify_parent(tsk, tsk->exit_signal);
        } else {
                autoreap = true;
        }

        tsk->exit_state = autoreap ? EXIT_DEAD : EXIT_ZOMBIE;
}

看这行代码
autoreap = thread_group_empty(tsk) && do_notify_parent(tsk, tsk->exit_signal);
因为进程B有个处于D状态的子线程,thread_group_empty返回false, 这行代码被短路了, do_notify_parent没有被调用,
因此进程B也就不会给进程A发送SIGCHLD信号,进程A没有机会调用waitpid回收进程B的状态。

奇怪的是内核为什么要这样实现,因为主进程退出之后所有的资源都会被回收,D状态的子线程也会退出,这岂不是会丢了个SIGCHLD信号?这样对父进程A不公平啊,

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
9 [报告]
发表于 2014-02-10 21:25 |只看该作者
本帖最后由 gaojl0728 于 2014-02-10 21:26 编辑

接8楼我前面的回复,

又研究了一下,SIGCHLD并没有丢失。
在主进程退出之后,主线程相关的资源被回收了, 但是进程地址空间还在,而且D状态的子线程也还在也还能运行。
当这个子线程从D状态恢复过来之后,会从系统调用返回,返回时会执行前面主进程B发送给他的SIGKILL信号,SIGKILL会导致do_group_exit->do_exit->exit_notify->release_task, 此时会调用do_notify_parent给父进程A补发SIGCHLD信号。

所以, 进程B之所以还显示为僵尸是因为D状态的子线程还没有从系统调用中返回,等他返回之后会发送SIGCHLD信号,最终会调用waitpid回收所有的资源。
可以用strace跟踪下D状态的子线程到底睡眠在哪个系统调用上。

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
10 [报告]
发表于 2014-02-11 10:09 |只看该作者
gaojl0728 发表于 2014-02-10 21:25
接8楼我前面的回复,

又研究了一下,SIGCHLD并没有丢失。

分析得很清楚~~,其实不存在不公平,A进程也可以不wait直接退出,退出后init会负责接管并回收资源。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP