C: fork with scanf



我试过这个代码

#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! %dn", x);
        else
            printf("Read: %dn", 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%.4Xn", corpse, status);
    }
    return 0;
}

我不明白你为什么会认为它被忽略了。

具体发生什么取决于使用的是什么。让我们看一下bash。

当有疑问时,使用strace(例如strace - tomeh bash + ./a.t 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 %dn",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的返回值

相关内容

  • 没有找到相关文章

最新更新