C++ 分叉后退出()或_exit()?
我正在编写一个程序,它需要与外部程序同时双向通信,即同时读取和写入外部程序 我创建了两个管道,一个用于向外部进程发送数据,一个用于从外部进程接收数据。分支子进程(成为外部程序)后,父进程再次分支。新的子级现在将数据写入外部程序的传出管道,父级现在从外部程序的传入管道读取数据以进行进一步处理 我听说使用出口(3)可能会导致缓冲区刷新两次,但我也担心使用出口(2)可能会使缓冲区保持未刷新状态。在我的程序中,分叉前后都有输出。在这种情况下,我应该使用哪个出口(3)或_出口(2) 下面是我的主要功能。为了简单起见,省略了#includes和辅助函数C++ 分叉后退出()或_exit()?,c++,fork,exit,C++,Fork,Exit,我正在编写一个程序,它需要与外部程序同时双向通信,即同时读取和写入外部程序 我创建了两个管道,一个用于向外部进程发送数据,一个用于从外部进程接收数据。分支子进程(成为外部程序)后,父进程再次分支。新的子级现在将数据写入外部程序的传出管道,父级现在从外部程序的传入管道读取数据以进行进一步处理 我听说使用出口(3)可能会导致缓冲区刷新两次,但我也担心使用出口(2)可能会使缓冲区保持未刷新状态。在我的程序中,分叉前后都有输出。在这种情况下,我应该使用哪个出口(3)或_出口(2) 下面是我的主要功能。为
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));
}
}
}
intmain(){
srand(时间(空));
(三);
cin>>n;
对于(double p=0.0;p你需要小心这类事情。exit()
对\u exit()
做了不同的事情,但又不同于\u exit()
,正如答案a所建议的那样,\u exit
(与\u exit
不同,注意大写E)不会调用atexit()
处理程序,或刷新任何输出缓冲区,删除临时文件等[实际上可能是atexit()
处理,但也可以作为直接调用完成,具体取决于C库代码的编写方式]
您的大多数输出都是通过write
完成的,从应用程序的角度来看,这应该是无缓冲的。但是您在fork()的子分支中调用cout,使用exit()通常是不正确的因为这会导致STDIO缓冲区被刷新两次,临时文件被意外删除。在C++代码中,情况更糟,因为静态对象的析构函数可能运行不正确。(有一些异常情况,比如守护进程,在这里,父进程应该调用而不是子项;适用于绝大多数情况的基本规则是,对于main中的每个条目,exit()只应调用一次。)可能的@hvd副本:不,我不这么认为。链接的副本是关于处理错误的。这种情况似乎与错误无关(虽然子进程中的错误处理似乎有点欠缺…@MatstPetersson我不明白其他问题是如何处理错误的,你能详细说明吗?无论如何,我认为公认答案中的观点适用于这里。好吧,这是关于“当某种形式的exec返回时你会怎么做”,这是一个错误条件,因为“exec”将替换现有进程。这一个更复杂,因为在仍作为分支进程执行的子进程中有输出。您不能只使用\u exit()
在这种情况下也是如此。@Matstpeterson另一个问题的输出也在子进程中进行:它调用perror
。是的,在这个问题中,输出是在错误条件下发生的,而在这个问题中不是在错误条件下发生的,但我不认为这有什么区别。实现只知道输出是编写的,它是不知道也无法知道它是否是错误条件。(事实上,根据具体的exec
,程序员可能也无法知道它是否是错误条件!)我的代码仅供内部使用(不是应用程序代码),因此为了简单起见,我省略了错误检查。然而,对于我的代码来说,准确地输出我想要做的事情是至关重要的,因为它将被外部程序解析。