调用 fork() 后函数的 return 值的可见性
Visibility of a function's return value after a call to fork()
当使用fork()
创建一个新的子进程时,我们得到一个pid_t
返回表明我们是在子进程(pid == 0
)还是父进程(pid > 0
) 在调用 fork()
完成后。总的来说,我在解决这个问题时遇到了一些麻烦,但特别难以找到以下问题的答案:
- 在函数中包装对
fork()
的调用时,该函数的调用代码(永远)是否会看到 child 中的 return 值fork()
? 之后的代码部分
为了说明,请参阅我编写的以下函数。我不确定调用 process/code 是否会收到 -1
return 值之一,这些值可以从代码。
/*
* 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
语句在 child 中执行,它将返回给 popen_noshell
的调用者在 child 中(以及在 parent 中)。这可能不是您想要的,它们可能应该替换为 _exit(-1)
当使用fork()
创建一个新的子进程时,我们得到一个pid_t
返回表明我们是在子进程(pid == 0
)还是父进程(pid > 0
) 在调用 fork()
完成后。总的来说,我在解决这个问题时遇到了一些麻烦,但特别难以找到以下问题的答案:
- 在函数中包装对
fork()
的调用时,该函数的调用代码(永远)是否会看到 child 中的 return 值fork()
? 之后的代码部分
为了说明,请参阅我编写的以下函数。我不确定调用 process/code 是否会收到 -1
return 值之一,这些值可以从代码。
/*
* 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
语句在 child 中执行,它将返回给 popen_noshell
的调用者在 child 中(以及在 parent 中)。这可能不是您想要的,它们可能应该替换为 _exit(-1)