我试过这个代码
#include <stdio.h> #include <sys/types.h> int main(){ int x=3; pid_t pid0=getpid(); pid_t pid1=0; if(fork()==0){ pid1=getpid(); } if(getpid()==pid1){ scanf("%d",&x); printf("%d",x); } return 0; }
而scanf
指令完全被忽略。 它只是打印旧的x是3 。 有人可以向我解释这里发生了什么吗?
这里对代码进行了大部分的修改。 它检查scanf()
工作,调用getpid()
的次数少一些,并且更仔细地报告事情。 而且,父母在退出之前等待孩子退出。
样品运行(我称之为程序fork7
):
$ ./fork7 <<< '' Parent (32976 - child 32977) Child (32977) Oops! 3 Child 32977: 0x0000 $ ./fork7 <<< 99 Parent (32978 - child 32979) Child (32979) Read: 99 Child 32979: 0x0000 $
代码( fork7.c
):
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main(void) { int x = 3; pid_t pid1; if ((pid1 = fork()) == 0) { printf("Child (%d)\n", (int)getpid()); if (scanf("%d", &x) != 1) printf("Oops! %d\n", x); else printf("Read: %d\n", x); } else { int corpse; int status; printf("Parent (%d - child %d)\n", (int)getpid(), (int)pid1); while ((corpse = wait(&status)) > 0) printf("Child %d: 0x%.4X\n", corpse, status); } return 0; }
我不明白为什么你会认为它被忽略。
究竟发生了什么取决于使用的是什么。 让我们来看看bash。
如果有疑问,请使用strace(例如strace -fo meh bash + ./a.out)
24852 ioctl(255, TIOCSPGRP <unfinished ...> 24909 read(0, <unfinished ...> 24852 <... ioctl resumed> , [24852]) = 0 24909 <... read resumed> 0xb774a000, 1024) = -1 EIO (Input/output error) 24852 rt_sigprocmask(SIG_SETMASK, [CHLD], <unfinished ...> 24909 fstat64(1, <unfinished ...> 24852 <... rt_sigprocmask resumed> NULL, 8) = 0 24909 <... fstat64 resumed> {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0 24852 ioctl(255, SNDCTL_TMR_TIMEBASE or TCGETS <unfinished ...> 24909 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 <unfinished ...> 24852 <... ioctl resumed> , {B38400 opost isig icanon echo ...}) = 0 24909 <... mmap2 resumed> ) = 0xb7749000 24852 ioctl(255, TIOCGWINSZ <unfinished ...> 24909 write(1, "[7]\n", 4 <unfinished ...>
24852显然是壳。 255是与终端相关的fd,在执行程序的过程中是0。 正如你在这里所看到的,一个ioctl被发出来重新获得对终端的控制,导致读取操作失败 。 如果你真的检查了错误,你将会了解它。
有一个方面的说明,我修改了数字,并将其括在[]中,以便它不能与输入的字符混淆。
弄清楚其他shell(比如zsh)发生了什么,这是读者的一个练习。
这是因为scanf
将会失败。 你可以通过这个简单的实验来确保这一点,只需在代码段中检查scanf
的返回值即可。
if(getpid() == pid1) { printf("return value of scanf %d\n",scanf("%d",&x)); printf("%d",x); }
输出你必须得到:
return value of scanf -1 //that means scanf got failed ? 3
现在问题是 为什么scanf
失败 ?
一旦父母退出,孩子被一个新的父母(通常是我认为是PID 1的那个 – / etc / init或类似的)接受。 而stdin
控制也被熄灭。 如果你真的想在你的子进程中获得输入(使用scanf
),强迫你的父母等待,直到它的子成功返回。 这可以实现为:
else { waitpid(-1,&status, WCONTINUED); return 0; }
还请确保你的孩子也应该返回。 有关waitpid
更多细节,请点击这里
NOTE
:总是建议您不要使用 scanf
。 如果您觉得您必须使用scanf
,那么您应该检查返回值,以确定在转换之前是否发生了输入错误。 而且请经常检查fork
的返回值。