- 论坛徽章:
- 3
|
回复 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不公平啊, |
|