C++ 分叉后退出()或_exit()?

C++ 分叉后退出()或_exit()?,c++,fork,exit,C++,Fork,Exit,我正在编写一个程序,它需要与外部程序同时双向通信,即同时读取和写入外部程序 我创建了两个管道,一个用于向外部进程发送数据,一个用于从外部进程接收数据。分支子进程(成为外部程序)后,父进程再次分支。新的子级现在将数据写入外部程序的传出管道,父级现在从外部程序的传入管道读取数据以进行进一步处理 我听说使用出口(3)可能会导致缓冲区刷新两次,但我也担心使用出口(2)可能会使缓冲区保持未刷新状态。在我的程序中,分叉前后都有输出。在这种情况下,我应该使用哪个出口(3)或_出口(2) 下面是我的主要功能。为

我正在编写一个程序,它需要与外部程序同时双向通信,即同时读取和写入外部程序

我创建了两个管道,一个用于向外部进程发送数据,一个用于从外部进程接收数据。分支子进程(成为外部程序)后,父进程再次分支。新的子级现在将数据写入外部程序的传出管道,父级现在从外部程序的传入管道读取数据以进行进一步处理

我听说使用出口(3)可能会导致缓冲区刷新两次,但我也担心使用出口(2)可能会使缓冲区保持未刷新状态。在我的程序中,分叉前后都有输出。在这种情况下,我应该使用哪个出口(3)或_出口(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));
        }
    }
}
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
,程序员可能也无法知道它是否是错误条件!)我的代码仅供内部使用(不是应用程序代码),因此为了简单起见,我省略了错误检查。然而,对于我的代码来说,准确地输出我想要做的事情是至关重要的,因为它将被外部程序解析。