fork() 进程中的 IO 流

发布于 2024-11-27 05:28:12 字数 1735 浏览 2 评论 0原文

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

问题是:为什么会这样,以及如何与 fork() 进程中的 stdinstdout 进行交互?

/* 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;
}

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

The following example code executes, but output from the forked process is not readable: nothing is shown on console until I press enter, and then "Read failed!" shows.

The question is: why is that, and how can I interact with stdin and stdout from the fork()'ed process?

/* 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;
}

Update:

Another example of strange behavior of IO streams:

/* 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 script:

#!/bin/sh

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

This one returns

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

Update 2:

Looks like this code does exactly what's needed:

#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;
}

The solution was to replace fork with vfork. I just don't know why is this one working...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

淡看悲欢离合 2024-12-04 05:28:12

我认为您需要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;
}

I think you want wait(2). As in

/* 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;
}
三生一梦 2024-12-04 05:28:12

这是因为您的子进程现在位于孤立进程组中,其中没有进程是 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):它是处理进程组4706的作业控制的shell。

当父进程死亡时,情况是这样的:

$ 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

This is because your child process is now in an orphaned process group, where no process is a direct child of the shell (who is supposed to do job-control).

Orphaned process group: Process group which doesn't have at least a member who has a parent not in the process group but within the same session (~ is a direct child of the shell).

While the parent and child are both running, the situation is like this:

$ 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

There are two processes, 4706 and 4707 on process group 4706. 4706 is a child of 27177, which is in the same session (27177), but different process group (27177): it's the shell that deals with job control for process group 4706.

When the parent dies, the situation is like this:

$ 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

There is only one process, 4664, in process group 4663, and its parent (init) isn't on the same session. The shell cannot deal with job control for this process group, therefore, read() and write() get EIO.

残龙傲雪 2024-12-04 05:28:12

如果您使用的是 UNIX/Linux,当 stdout 进入控制台时,它是行缓冲的。也就是说,除非执行以下任一操作,否则您看不到任何输出:

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

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

If you are on UNIX/Linux, when stdout goes into console it is line-buffered. That is, you don't see any output until you do either:

  • fflush(stdout)
  • prinf("\n")
  • stdout buffer overflows.

When stdout goes somewhere else (like pipe of file) it is fully-buffered, that is, printf("\n") does not flush the buffer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文