gpt4 book ai didi

C Linux 管道读取乱序。丢失和重复的输出

转载 作者:太空宇宙 更新时间:2023-11-04 08:00:12 29 4
gpt4 key购买 nike

我正在开发一个应用程序,它需要启动任意子进程并在它们运行时读取它们的输出。将其视为终端仿真器可能很有用,因为它必须能够在其整个生命周期中多次运行子进程并读回它们的输出,我希望它以与终端显示它的方式相同的方式读回它们的输出.

我也无法控制子进程的代码,所以我不能通过在子进程代码中更频繁地刷新来解决这个问题,尽管每次打印后刷新似乎最有帮助(全部?)的问题。

我设置了以下展示问题的小演示,但我也无法在这个小演示中修复它:

设置:

exerciser - 一个打印一些东西的程序,并启动一个也打印一些东西的子进程。它们的打印设置使得两个进程都可以缓冲“A”,除非标准输出在 fork 之前被刷新。

reader - 启动一个子进程并设置一个管道来读取它的输出。立即打印它从 child 那里读取的所有内容。 child 运行锻炼程序。

----终端输出----

<...>/pipe-testing$ ./exerciser
A: 10
B: 42
C: 42
C: 10
<...>/pipe-testing$ ./reader
READER...
A: 10
B: 42
C: 42
A: 10
C: 10

----练习器.cpp----

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

int main(){
int n = 10, status = 0;
fprintf(stdout, "A: %d\n", n);
if (fork() == 0){
n = 42;
fprintf(stdout, "B: %d\n", n);
}
else{
wait(&status);
}
fprintf(stdout, "C: %d\n", n);
return(0);
}

----阅读器.cpp----

#include <stdio.h>
#include <unistd.h>

int main(){
fprintf(stdout, "READER...\n");
fflush(stdout);

int pipe_fds[2];
if (pipe(pipe_fds) == -1){
fprintf(stdout, "failed to make pipe\n");
return(0);
}

pid_t child_pid = fork();
if (child_pid == -1){
fprintf(stdout, "failed to fork\n");
return(0);
}

#define PIPE_READ 0
#define PIPE_WRITE 1

if (child_pid == 0){
close(pipe_fds[PIPE_READ]);
dup2(pipe_fds[PIPE_WRITE], STDOUT_FILENO);
dup2(pipe_fds[PIPE_WRITE], STDERR_FILENO);

char *argv[] = {
"sh",
"-c",
"./exerciser",
0
};

if (execv("/bin/sh", argv) == -1){
fprintf(stdout, "failed to execv\n");
return(0);
}
}
else{
close(pipe_fds[PIPE_WRITE]);

char buffer[1024];
int capacity = sizeof(buffer);
for (;;){
ssize_t num = read(pipe_fds[PIPE_READ], buffer, capacity);
if (num == -1){
fprintf(stdout, "read error\n");
return(0);
}
else if (num == 0){
break;
}
else{
fprintf(stdout, "%.*s", (int)num, buffer);
fflush(stdout);
}
}
}

return(0);
}

最佳答案

I also don't have control over the code of the child processes, so I can't just solve this problem by flushing more often in the child process code although flushing after every print does seem to help most (all?) of the issues.

那就没办法了,因为问题出在子进程上。子进程调用 fork,为其子进程提供与它相同的输出流。然后两个进程写入同一个输出流,没有任何保护或同步。没有什么可以阻止 exerciser 父进程和子进程交替或同时写入它们的流。

这与在 shell 脚本中执行此操作没有什么不同:

echo -n "test" &
echo -n "ing" &

输出可能是“testing”,但也可能是“ingtest”或“tiensgt”或许多其他内容。

由于是 exerciser 进程执行此操作,因此如果您希望获得连贯的输出,则必须修复 exerciser 程序。除了首先不将困惑放入管道中之外,没有办法解开从管道中出来的困惑。

关于C Linux 管道读取乱序。丢失和重复的输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47243890/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com