【问题标题】:C++ wrong usage of close and dup2?C++ 错误使用 close 和 dup2?
【发布时间】:2021-07-23 07:03:35
【问题描述】:

我写了以下代码:

void execute() {
    std::cout << "smash pid is " << getpid() << std::endl;
}

int main()
{
    int pid=fork();
    if (pid==0)
    {
        int fd=open("my_file.txt", O_WRONLY | O_CREAT, 0666); // 3=my_file
        dup2(fd,1); // replace output stream
        close(fd); //close duplicate access to my_file
        execute();
        close (1); // close last access to my file
    }
    else if (pid>0)
    {
        std::cout << "Hello!" << std::endl;
    }
    return 0;
}

我的问题是我做事正确吗?主进程还能像往常一样访问终端打印吗?

我尝试添加我正在做的事情的注释,如果有不清楚的地方请告诉我。


版本 2:

int main()
{
    int pid=fork();
    if (pid==0)
    {
        close (1);
        int fd=open("my_file.txt", O_WRONLY | O_CREAT, 0666); // 3=my_file
        execute();
        close (1); // close last access to my file
    }
    else if (pid>0)
    {
        std::cout << "Hello!" << std::endl;
    }
    return 0;
}

【问题讨论】:

  • 您正在尝试将标准输出重定向到子进程中的文本文件,对吗?版本 1 看起来不错。问:版本 1 是否按您的预期工作?问:版本 2 是否失败?问:你为什么首先这样做?你想在这里展示什么?

标签: c++ linux file unix


【解决方案1】:

我的问题是我做事正确吗?

您的孩子会将其输出定向到打开的文件中,而父母会写“Hello!”到在启动时提供给程序的stdout。看起来这就是你想要的,所以,是的。

我会使用pid_t 而不是int 作为进程ID,但在不同平台上可能会有所不同。

主进程还能像往常一样访问终端打印吗?

是的。子进程中的dup2 不会以任何方式影响父进程。

一个音符。使用fileno(stdout) 而不是1

dup2(fd, fileno(stdout));
// and
close(fileno(stdout)); // not needed really

int fileno(FILE*) 函数从标准FILE*(即stdout)返回内部文件描述符。这只是一种让代码读者更清楚的方式。


但是,您可以改用标准 C++ 函数 std::freopenstdout 重定向到文件。

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

#include <cstdio>    // std::freopen
#include <iostream>

void execute() {
    std::cout << "smash pid is " << getpid() << std::endl;
    system("echo the redirect is inherited by the grand children too");
}

int main() {
    pid_t pid = fork();

    if(pid < 0) {                   // check for errors
        std::perror("fork failed");
        return 1;
    }

    if(pid == 0) {                  // child
        // using std::freopen
        if(std::freopen("my_file.txt", "w", stdout) == nullptr) {
            std::perror("freopen failed");
            return 1;
        }

        execute();

        return 0;
    }

    // parent
    std::cout << "Parent says hello!\n";

    // wait for child
    int wstatus;
    if(waitpid(pid, &wstatus, 0) == pid) {
        std::cout << "child exited with status " << wstatus << '\n';
    } else {
        std::perror("waitpid failed");
    }
}

【讨论】:

  • 知道了,你能建议对版本 1 进行任何修改吗?
  • @daniel 当然——我会将裸文件描述符封装在一个支持更高级别的这些操作的 RAII 类中——但同样,这是一个全新的、不同的问题。这种类型的问题更适合codereview - 不过有两件事。您应该始终检查错误(opendup2 都可能失败),您可以在父进程中添加 waitwaitpid 以等待子进程完成。
  • @TedLyngmo:他已经拥有一个支持这些操作的文件封装。即std::cout上的rdbuf()操作。
  • @BenVoigt 我猜在某种程度上是正确的。我从来没有弄清楚如何真正重定向 ostream。当使用fork() 后经常使用exec 然后交换rdbufs 并没有帮助。在 OP:s 简化代码中,它可以正常工作,同意。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-26
  • 1970-01-01
相关资源
最近更新 更多