当子进程fork()
时,父进程可以wait()
以完成子进程。假设,只是为了进行实验,而不是wait()
,如果我们创建父进程sleep()
,那么为什么它不起作用呢?
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t child_id ;
child_id = fork() ;
if (child_id == 0)
{
printf("\nChild process");
printf("\nChild process exiting");
}
else
{
printf("\nParent process");
sleep(10);
printf("\nParent process exiting");
}
}
我猜SIGCHLD
信号导致父进程从sleep()
唤醒。但是,为什么,它是一个子进程,它们有不同的地址空间和资源,那么它如何干扰父进程的问题呢?
答案 0 :(得分:3)
注意系统之间的差异。通过在Mac OS X 10.9上运行代码的这种小修改,孩子死亡不会影响父级中的sleep(10)
:
Parent process
Child process
Child process exiting 1384590368
Parent process exiting 1384590378
如您所见,父母比孩子晚了10秒左右。
#include <stdio.h>
#include <unistd.h>
#include <time.h>
int main(void)
{
pid_t child_id;
child_id = fork();
if (child_id == 0)
{
printf("\nChild process");
printf("\nChild process exiting %ld\n", (long)time(0));
}
else
{
printf("\nParent process\n");
sleep(10);
printf("\nParent process exiting %ld\n", (long)time(0));
}
}
我在运行古老版本Linux的VM(2008年2.6.16.60内核)上有相同的行为;父母在孩子出生后10秒就去世了。
所以,如果你问的行为“为什么它不起作用?”是'父母立刻退出孩子死了',那么你的代码并没有证明它确实退出了两个系统中的任何一个。我不能断然说父母不会在你的系统上迅速死亡,但这是出乎意料的。
您可能会发现此程序对于研究SIGCHLD信号的行为很有用:
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
static siginfo_t sig_info;
static volatile sig_atomic_t sig_num;
static void *sig_ctxt;
static void catcher(int signum, siginfo_t *info, void *vp)
{
sig_num = signum;
sig_info = *info;
sig_ctxt = vp;
}
static void set_handler(int signum)
{
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = catcher;
sigemptyset(&sa.sa_mask);
if (sigaction(signum, &sa, 0) != 0)
{
int errnum = errno;
fprintf(stderr, "Failed to set signal handler (%d: %s)\n", errnum, strerror(errnum));
exit(1);
}
}
static void prt_interrupt(FILE *fp)
{
if (sig_num != 0)
{
fprintf(fp, "Signal %d from PID %d\n", sig_info.si_signo, (int)sig_info.si_pid);
sig_num = 0;
}
}
static void five_kids(void)
{
for (int i = 0; i < 5; i++)
{
pid_t pid = fork();
if (pid < 0)
break;
else if (pid == 0)
{
printf("PID %d - exiting with status %d\n", (int)getpid(), i);
exit(i);
}
else
{
int status = 0;
pid_t corpse = wait(&status);
printf("Child: %d; Corpse: %d; Status = 0x%.4X\n", pid, corpse, (status & 0xFFFF));
prt_interrupt(stdout);
fflush(0);
}
}
}
int main(void)
{
printf("SIGCHLD set to SIG_DFL\n");
signal(SIGCHLD, SIG_DFL);
five_kids();
printf("SIGCHLD set to SIG_IGN\n");
signal(SIGCHLD, SIG_IGN);
five_kids();
printf("SIGCHLD set to catcher()\n");
set_handler(SIGCHLD);
five_kids();
return(0);
}
再次在Mac OS X 10.9上,它产生了:
SIGCHLD set to SIG_DFL
PID 52345 - exiting with status 0
Child: 52345; Corpse: 52345; Status = 0x0000
PID 52346 - exiting with status 1
Child: 52346; Corpse: 52346; Status = 0x0100
PID 52347 - exiting with status 2
Child: 52347; Corpse: 52347; Status = 0x0200
PID 52348 - exiting with status 3
Child: 52348; Corpse: 52348; Status = 0x0300
PID 52349 - exiting with status 4
Child: 52349; Corpse: 52349; Status = 0x0400
SIGCHLD set to SIG_IGN
PID 52350 - exiting with status 0
Child: 52350; Corpse: -1; Status = 0x0000
PID 52351 - exiting with status 1
Child: 52351; Corpse: -1; Status = 0x0000
PID 52352 - exiting with status 2
Child: 52352; Corpse: -1; Status = 0x0000
PID 52353 - exiting with status 3
Child: 52353; Corpse: -1; Status = 0x0000
PID 52354 - exiting with status 4
Child: 52354; Corpse: -1; Status = 0x0000
SIGCHLD set to catcher()
PID 52355 - exiting with status 0
Child: 52355; Corpse: -1; Status = 0x0000
Signal 20 from PID 52355
Child: 52356; Corpse: 52355; Status = 0x0000
PID 52356 - exiting with status 1
Child: 52357; Corpse: -1; Status = 0x0000
PID 52357 - exiting with status 2
Signal 20 from PID 52356
Child: 52358; Corpse: 52357; Status = 0x0200
Signal 20 from PID 52357
PID 52358 - exiting with status 3
Child: 52359; Corpse: 52356; Status = 0x0100
PID 52359 - exiting with status 4
Linux上的行为类似 - 不完全相同:
SIGCHLD set to SIG_DFL
PID 14645 - exiting with status 0
Child: 14645; Corpse: 14645; Status = 0x0000
PID 14646 - exiting with status 1
Child: 14646; Corpse: 14646; Status = 0x0100
PID 14647 - exiting with status 2
Child: 14647; Corpse: 14647; Status = 0x0200
PID 14648 - exiting with status 3
Child: 14648; Corpse: 14648; Status = 0x0300
PID 14649 - exiting with status 4
Child: 14649; Corpse: 14649; Status = 0x0400
SIGCHLD set to SIG_IGN
PID 14650 - exiting with status 0
Child: 14650; Corpse: -1; Status = 0x0000
PID 14651 - exiting with status 1
Child: 14651; Corpse: -1; Status = 0x0000
PID 14652 - exiting with status 2
Child: 14652; Corpse: -1; Status = 0x0000
PID 14653 - exiting with status 3
Child: 14653; Corpse: -1; Status = 0x0000
PID 14654 - exiting with status 4
Child: 14654; Corpse: -1; Status = 0x0000
SIGCHLD set to catcher()
PID 14655 - exiting with status 0
Child: 14655; Corpse: 14655; Status = 0x0000
Signal 17 from PID 14655
PID 14656 - exiting with status 1
Child: 14656; Corpse: 14656; Status = 0x0100
Signal 17 from PID 14656
PID 14657 - exiting with status 2
Child: 14657; Corpse: 14657; Status = 0x0200
Signal 17 from PID 14657
PID 14658 - exiting with status 3
Child: 14658; Corpse: 14658; Status = 0x0300
Signal 17 from PID 14658
PID 14659 - exiting with status 4
Child: 14659; Corpse: 14659; Status = 0x0400
Signal 17 from PID 14659
答案 1 :(得分:0)
请仔细阅读 <{3}},fork(2),execve(2) ...
的手册页 wait
系统调用不只是被动地等待子进程。它清除内部内核状态以避免wait(2)。
另请使用zombie processes,例如在您的计划中为strace -f
。
花几个小时阅读一本好书,例如strace(1)。理解过程需要很长时间,我们没有那么多时间教给你。请阅读书籍并继续像你一样进行实验!另外,花一些时间阅读自由软件的源代码(如某些shell的源代码-e.g. bash
或sash
)
fork
的失败(所以总是处理fork
的三个可能的回复:{{1在子进程中,父进程中为==0
,失败时为>0
。考虑使用Advanced Linux Programming(在shell中调用ulimit)来触发此类错误条件以进行测试。