c - 调用 fork() 后函数返回值的可见性

标签 c fork child-process

当使用fork()创建一个新的子进程时,我们得到一个pid_t返回,表明我们是否在子进程中(pid == 0)或父进程(pid > 0)在调用fork()完成后。一般来说,我在理解这一点上遇到了一些麻烦,但特别是很难找到以下问题的答案:

  • 在函数中包装对 fork() 的调用时,该函数的调用代码(曾经)是否会看到代码的部分中的返回值在fork()之后?

为了说明这一点,请参阅我编写的以下函数。我不确定调用进程/代码是否会收到可以从 else if (pid == 0) { ... 中返回的 -1 返回值之一} 部分代码。

/*
 * Opens the process `cmd` similar to popen() but does not invoke a shell.
 * Instead, wordexp() is used to expand the given command, if necessary.
 * If successful, the process id of the new process is being returned and the 
 * given FILE pointers are set to streams that correspond to pipes for reading 
 * and writing to the child process, accordingly. Hand in NULL for pipes that
 * should not be used. On error, -1 is returned.
 */
pid_t popen_noshell(const char *cmd, FILE **out, FILE **err, FILE **in)
{
    if (!cmd || !strlen(cmd)) return -1;

    // 0 = read end of pipes, 1 = write end of pipes
    int pipe_stdout[2];
    int pipe_stderr[2];
    int pipe_stdin[2];

    if (out && (pipe(pipe_stdout) < 0)) return -1;
    if (err && (pipe(pipe_stderr) < 0)) return -1;
    if (in  && (pipe(pipe_stdin)  < 0)) return -1;

    pid_t pid = fork();
    if (pid == -1)
    {
        return -1;
    }
    else if (pid == 0) // child
    {    
        // redirect stdout to the write end of this pipe
        if (out)
        {
            if (dup2(pipe_stdout[1], STDOUT_FILENO) == -1) return -1;
            close(pipe_stdout[0]); // child doesn't need read end
        }
        // redirect stderr to the write end of this pipe
        if (err)
        {
            if (dup2(pipe_stderr[1], STDERR_FILENO) == -1) return -1;
            close(pipe_stderr[0]); // child doesn't need read end
        }
        // redirect stdin to the read end of this pipe
        if (in)
        {
            if (dup2(pipe_stdin[0], STDIN_FILENO) == -1) return -1;
            close(pipe_stdin[1]); // child doesn't need write end
        }

        wordexp_t p;
        if (wordexp(cmd, &p, 0) != 0) return -1;

        execvp(p.we_wordv[0], p.we_wordv);
        _exit(1);
    }
    else // parent
    {
        if (out)
        {
            close(pipe_stdout[1]); // parent doesn't need write end
            *out = fdopen(pipe_stdout[0], "r");
        }
        if (err)
        {
            close(pipe_stderr[1]); // parent doesn't need write end
            *err = fdopen(pipe_stderr[0], "r");
        }
        if (in)
        {
            close(pipe_stdin[0]); // parent doesn't need read end
            *in = fdopen(pipe_stdin[1], "w");
        }
        return pid;
    }
}

最佳答案

fork 复制整个调用堆栈,因此如果在子级中执行这些 return -1 语句之一,它将返回给 的调用者popen_noshell 在子级(以及父级)中。这可能不是您想要的,它们可能应该替换为 _exit(-1)

关于c - 调用 fork() 后函数返回值的可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59705298/

相关文章:

在 C 中计算斐波那契递归调用的次数

c - fork系统调用

bash - 如何等待孙进程 (`bash` retval 在 Perl 中由于 SIG CHLD 变为 -1)

c++ - 游戏循环不工作 ncurses

c - 为什么在 ioctl 命令中从用户空间复制结构失败?

c++ - 优化稀疏矩阵中的对数熵计算

C: fork() 子进程

c - 使用管道将多个字符串发送到子进程

c - Fork 和 execlp 不执行我的程序?

javascript - NodeJS 与 Child_Process - 如何转义我的命令