当从stdin读取时子进程变为孤立时的奇怪行为

时间:2016-02-24 09:31:38

标签: c linux fork stdin system-calls

以下是代码:

// after fork:
else if (pid > 0) // parent
{
    char buff[READ_SIZE];
    write(STDOUT_FILENO, "parent\n", 7);

    int r = read(STDIN_FILENO, buff, READ_SIZE);
    if (r == -1)
        perror("parent");
}
else // child
{
    char buff[READ_SIZE];
    write(STDOUT_FILENO, "child\n", 6);

    int r = read(STDIN_FILENO, buff, READ_SIZE);
    if (r == -1)
        perror("child");

    sprintf(buff, "\n%d", r);
    write(STDOUT_FILENO, buff, 2);
}

这是输出:

$ ./forktest
parent
child
abc <-- input goes to parent, parent exits
$   <-- both child and terminal waiting for input, presumably

此时,只要按任意键(不按Enter键),我就会:

$ ./forktest
parent
child
abc
$ 
1  <-- the child has read just 1 character

这意味着孩子的read()只在一次按键后没有回复就结束了。

为什么?

PS。我知道正确的做法是让父母为孩子等待()。我只是好奇这里到底发生了什么。

2 个答案:

答案 0 :(得分:0)

如果stdin不再有效,为什么read()不返回-1?

stdin 始终有效,直到您关闭终端应用程序。

stdin是由您的终端创建的,而不是bash,而不是父级。只要您的终端处于活动状态,stdin就会激活

为什么read()在一次按键后结束,即使我还没有按下回车键呢?

大多数shell(bash / dash / zsh)将tty设置为逐字节模式读取,当你按任意键时,read会立即返回,因为它们正在自动完成。

当shell要启动程序时,它将tty设置为行模式,程序逐行读取。

但是一旦父进程退出,shell就会将tty重置为字节模式,因为你的孩子和shell共享相同的tty,它也会影响你的孩子,所以你的孩子会读取一个字符。

答案 1 :(得分:0)

您的shell喜欢以原始模式工作,但会将终端设置为熟化模式以生成程序。你可以在任何地方阅读有关原始模式和熟食模式的信息。但简单地说,在原始模式中,输入是逐个字符的,而在熟食模式下,它是逐行的。

那会发生什么?省略多余的事件:

  • shell将终端设置为熟化模式。
  • shell运行你的程序。
  • 您的程序会产生一个孩子然后退出。
  • shell取回控制权。
  • shell将终端置于原始模式。
  • 您输入一个角色。
  • 您的子进程会抓住它。