在fork()'ed进程中的IO流

时间:2011-07-29 10:58:29

标签: c linux console io fork

以下示例代码执行,但分叉进程的输出不可读:控制台上没有显示任何内容,直到我按Enter键,然后“读取失败!”示出。

问题是:为什么会这样,我如何与stdin'ed过程中的stdoutfork()进行互动?

/* example1.c */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main() {
    pid_t pid = fork();

    if (!pid) {
        // child

        char s[64];
        printf("Enter something: ");
        char *res = fgets(s, 64, stdin);
        if (!res) {
            printf("Read failed!\n");
        } else {
            printf("You entered: %s", s);
        }
    }

    return 0;
}

更新

IO流的奇怪行为的另一个例子:

/* example2.c */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main() {
    pid_t pid = fork();

    if (!pid) {
        // child

        char *argv[] = {
            "-c",
            "/home/user/echo.sh",
            NULL
        };

        execv("/bin/sh", argv);
    }
    return 0;
}

echo.sh脚本:

#!/bin/sh

read -p "Enter something: " INPUT
echo "You entered $INPUT"

这个返回

Enter something: /home/user/echo.sh: line 3: read: read error: 0: Input/output error
You entered

更新2:

看起来这段代码完全符合我们的要求:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main() {
    pid_t pid = vfork();
    if (!pid) {
        // child
        system("/home/user/echo.sh");
    }
    return 0;
}

解决方案是将fork替换为vfork。我只是不知道为什么这个工作......

3 个答案:

答案 0 :(得分:2)

我想你想要wait(2)。如在

/* example1.c */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main() {
    int status;
    pid_t pid = fork();

    if (!pid) {
        // child

        char s[64];
        printf("Enter something: ");
        char *res = fgets(s, 64, stdin);
        if (!res) {
            printf("Read failed!\n");
        } else {
            printf("You entered: %s", s);
        }
    }
    else
    {
        while (wait(&status) != pid);
    }
    return 0;
}

答案 1 :(得分:1)

这是因为您的子进程现在位于孤立进程组中,其中没有进程是shell的直接子进程(谁应该进行作业控制)。

孤立进程组:至少没有成员的进程组,其中父级不在进程组中但在同一会话中(〜是直接的孩子的外壳)。

虽然父母和孩子都在跑,但情况是这样的:

$ ps fax -o pid,pgid,sid,ppid,tty,stat,time,cmd
27177 27177 27177 32170 pts/6    Ss   00:00:00  |   \_ /bin/bash
 4706  4706 27177 27177 pts/6    S+   00:00:00  |       \_ ./ex1
 4707  4706 27177  4706 pts/6    S+   00:00:00  |           \_ ./ex1

进程组4706上有两个进程4706和4707. 4706是27177的子进程,它位于同一个会话(27177)中,但进程组不同(27177):它是处理作业控制的shell进程组4706。

当父母去世时,情况如下:

$ ps fax -o pid,pgid,sid,ppid,tty,stat,time,cmd
27177 27177 27177 32170 pts/6    Ss+  00:00:00  |   \_ /bin/bash
 4664  4663 27177     1 pts/6    S    00:00:00 ./ex1

进程组4663中只有一个进程4664,其父进程(init)不在同一会话中。 shell无法处理此流程组的作业控制,因此read()write()获取EIO

答案 2 :(得分:0)

如果你在UNIX / Linux上,当stdout进入控制台时,它是行缓冲的。也就是说,在您执行任何操作之前,您看不到任何输出:

  • fflush(stdout)
  • prinf("\n")
  • stdout缓冲区溢出。

当stdout到达其他地方(比如文件管道)时,它是完全缓冲的,即printf("\n")不会刷新缓冲区。

相关问题