微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

linux – 父进程的sleep被subprocess中断

一个subprocess是fork() ,父进程可以wait()来完成subprocess。 假设,只是为了试验,而不是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()唤醒sleep() 。 但是,为什么呢,这是一个孩子的过程,他们有不同的地址空间和资源,那么它怎么能干涉父母的过程呢?

在库和程序之间共享variables

Windows Phone 8,覆盖旧的应用程序?

INPUT,INPUT_KEYBOARD,IP没有在这个范围内声明

替代jpeg_read_header libjpeg

放弃使用信号的function实现

注意系统之间的差异。 在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 %ldn",(long)time(0)); } else { printf("nParent processn"); sleep(10); printf("nParent process exiting %ldn",(long)time(0)); } }

在运行古老版本的Linux的虚拟机(从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 %dn",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 %dn",(int)getpid(),i); exit(i); } else { int status = 0; pid_t corpse = wait(&status); printf("Child: %d; Corpse: %d; Status = 0x%.4Xn",pid,corpse,(status & 0xFFFF)); prt_interrupt(stdout); fflush(0); } } } int main(void) { printf("SIGCHLD set to SIG_DFLn"); signal(SIGCHLD,SIG_DFL); five_kids(); printf("SIGCHLD set to SIG_IGNn"); 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

请仔细阅读fork(2) , execve(2)的手册页, 等待(2) …

wait系统调用不仅仅是被动地等待子进程。 它清理内部的内核状态,以避免僵尸进程 。

在程序中也使用strace(1),例如strace -f 。

花几个小时阅读一本好书,比如高级Linux编程 。 理解过程需要数小时,而我们没有多少时间教给你。 请阅读书籍,继续像你一样试验! 另外,花点时间阅读免费软件的源代码(如某些shell的源代码 – 例如bash或sash )

顺便说一句,你的程序在另一个问题上是错误的:你应该总是测试fork失败(所以总是处理fork的三个可能的返回值:子进程中的==0 >0 ,父进程中的<0 ,失败时的<0 )。 考虑使用ulimit (在shell内部调用setrlimit(2) )来触发这样一个错误条件来进行测试。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐