【发布时间】:2013-04-28 14:59:50
【问题描述】:
我正在编写一个程序,它需要同时与外部程序进行双向通信,即同时读取和写入外部程序。
我创建了两个管道,一个用于向外部进程发送数据,一个用于从外部进程接收数据。在 fork 成为外部程序的子进程之后,父进程再次 fork。新的子进程现在将数据写入到外部程序的传出管道中,而父进程现在从外部程序的传入管道中读取数据以进行进一步处理。
我听说使用 exit(3) 可能会导致缓冲区被刷新两次,但是我也担心使用 _exit(2) 可能会使缓冲区未刷新。在我的程序中,分叉前后都有输出。在这种情况下,我应该使用哪个 exit(3) 或 _exit(2)?
以下是我的主要功能。为简单起见,省略了#includes 和辅助函数。
int main() {
srand(time(NULL));
ssize_t n;
cin >> n;
for (double p = 0.0; p <= 1.0; p += 0.1) {
string s = generate(n, p);
int out_fd[2];
int in_fd[2];
pipe(out_fd);
pipe(in_fd);
pid_t child = fork();
if (child) {
// parent
close(out_fd[0]);
close(in_fd[1]);
if (fork()) {
close(out_fd[1]);
ssize_t size = 0;
const ssize_t block_size = 1048576;
char buf[block_size];
ssize_t n_read;
while ((n_read = read(in_fd[0], buf, block_size)) != 0) {
size += n_read;
}
size += n_read;
close(in_fd[0]);
cout << "p = " << p << "; compress ratio = " << double(size) / double(n) << '\n'; // data written before forking (the loop continues to fork)
} else {
write(out_fd[1], s.data(), s.size()); // data written after forking
exit(EXIT_SUCCESS); // exit(3) or _exit(2) ?
}
} else {
// child
close(in_fd[0]);
close(out_fd[1]);
dup2(out_fd[0], STDIN_FILENO);
dup2(in_fd[1], STDOUT_FILENO);
close(STDERR_FILENO);
execlp("xz", "xz", "-9", "--format=raw", reinterpret_cast<char *>(NULL));
}
}
}
【问题讨论】:
-
@hvd:不,我不这么认为。链接的副本是关于处理错误的。这个案例好像不是关于错误的(虽然子进程中的错误处理好像有点欠缺……
-
@MatsPetersson 我不明白其他问题是如何处理错误的,你能详细说明一下吗?无论如何,我认为在接受的答案中提出的观点在这里适用。
-
好的,这是关于“当某种形式的 exec 返回时你会做什么”,这是一个错误条件,因为“exec”将替换现有进程。这个更复杂,因为子进程中的输出仍在作为分叉进程执行。在这种情况下,你也不能只使用
_exit()。 -
@MatsPetersson 另一个问题在子进程中也有输出:它调用
perror。是的,输出发生在那个问题的错误条件下,而不是这个问题的错误条件下,但我看不出这有什么区别。实现所知道的只是输出已写入,它不知道也无法知道它是否是错误条件。 (实际上,根据具体的exec,程序员可能也无从得知是否是错误情况!)