通过等待每个进程的 return 代码创建多个管道
Make multiple pipe with waiting for return code of each process
我想使用 execve、dup2、[=38= 在 C 中重现 UNIX Shell 的管道系统]fork、waitpid & pipe 函数。
对,例如这个命令:/bin/ls -l | /usr/bin/head -2 | /usr/bin/wc
被转载为:
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int add_child_process(char **argv, int in, int out, char **envp)
{
int pid;
pid = fork();
if (pid == 0)
{
if (in != 0)
{
dup2(in, 0);
}
if (out != 1)
{
dup2(out, 1);
}
if (execve(argv[0], argv, envp) == -1)
perror("Execve failed");
}
else
return (pid);
}
int main(int av, char **ag, char **envp)
{
int in;
int pipes[2];
char *argv[3];
int pids[3];
/** Launch first process that read on original stdin (0) and write on out of pipe **/
pipe(pipes);
argv[0] = "/bin/ls";
argv[1] = "-l";
argv[2] = NULL;
pids[0] = add_child_process(argv, 0, pipes[1], envp);
close(pipes[1]);
in = pipes[0];
/** Launch second process that read on in of old pipe and write on out of new pipe **/
pipe(pipes);
argv[0] = "/usr/bin/head";
argv[1] = "-2";
argv[2] = NULL;
pids[1] = add_child_process(argv, in, pipes[1], envp);
close(in);
close(pipes[1]);
in = pipes[0];
/** Launch last process that read on in of old pipe and write on original stdout (1) **/
argv[0] = "/usr/bin/wc";
argv[1] = NULL;
pids[2] = add_child_process(argv, in, 1, envp);
close(in);
/** Wait for all process end to catch all return codes **/
int return_code;
waitpid(pids[0], &return_code, 0);
printf("Process 0 return : %d\n", return_code);
waitpid(pids[1], &return_code, 0);
printf("Process 1 return : %d\n", return_code);
waitpid(pids[2], &return_code, 0);
printf("Process 2 return : %d\n", return_code);
}
工作,输出为:
2 11 60
Process 0 return : 0
Process 1 return : 0
Process 2 return : 0
喜欢echo "/bin/ls -l | /usr/bin/head -2 | /usr/bin/wc" | bash
但对于像 ping google.com | head -2 | wc
这样的阻塞命令,它显示为:
2 16 145
并保持封锁状态。
这是使用此命令更新的主要内容:
int main(int av, char **ag, char **envp)
{
int in;
int pipes[2];
char *argv[3];
int pids[3];
/** Launch first process that read on original in (0) and write on out of pipe **/
pipe(pipes);
argv[0] = "/bin/ping";
argv[1] = "google.com";
argv[2] = NULL;
pids[0] = add_child_process(argv, 0, pipes[1], envp);
close(pipes[1]);
in = pipes[0];
/** Launch second process that read on in of old pipe and write on out of new pipe **/
pipe(pipes);
argv[0] = "/usr/bin/head";
argv[1] = "-2";
argv[2] = NULL;
pids[1] = add_child_process(argv, in, pipes[1], envp);
close(in);
close(pipes[1]);
in = pipes[0];
/** Launch last process that read on in of old pipe and write on original stdout (1) **/
argv[0] = "/usr/bin/wc";
argv[1] = NULL;
pids[2] = add_child_process(argv, in, 1, envp);
close(in);
/** Wait for all process end to catch all return codes **/
int return_code;
waitpid(pids[0], &return_code, 0);
printf("Process 0 return : %d\n", return_code);
waitpid(pids[1], &return_code, 0);
printf("Process 1 return : %d\n", return_code);
waitpid(pids[2], &return_code, 0);
printf("Process 2 return : %d\n", return_code);
}
我真的不明白为什么会出现这种行为,例如在 Bash 中:echo "ping google.com | head -2 | wc" | bash
显示 2 16 145
而不是卡住。
如何处理阻塞命令?我需要根据最后一个错误代码获取我的进程的所有 return 代码,以便 return return。
您的 add_child_process()
函数应该 return PID;它没有。它还应该在 execve()
之后进行错误处理,以防程序无法执行。
第一个解决方案——不够好
有了这些修复(以及其他各种更改以超过我的最低编译警告级别——例如 #include <stdio.h>
以便在使用之前有一个 printf()
的声明),我大致得到预期的输出。
我用这段代码(源文件pc67.c
)来测试:
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
static
int add_child_process(char **argv, int in, int out, char **envp)
{
int pid;
pid = fork();
if (pid == 0)
{
if (in != 0)
{
dup2(in, 0);
}
if (out != 1)
{
dup2(out, 1);
}
execve(argv[0], argv, envp);
abort();
}
return pid;
}
int main(int av, char **ag, char **envp)
{
int in;
int pipes[2];
char *argv[3];
int pids[3];
assert(ag[av] == 0);
/** Launch first process that read on original stdin (0) and write on out of pipe **/
pipe(pipes);
argv[0] = "/bin/ls";
argv[1] = "-l";
argv[2] = NULL;
pids[0] = add_child_process(argv, 0, pipes[1], envp);
close(pipes[1]);
in = pipes[0];
/** Launch second process that read on in of old pipe and write on out of new pipe **/
pipe(pipes);
argv[0] = "/usr/bin/head";
argv[1] = "-2";
argv[2] = NULL;
pids[1] = add_child_process(argv, in, pipes[1], envp);
close(in);
close(pipes[1]);
in = pipes[0];
/** Launch last process that read on in of old pipe and write on original stdout (1) **/
argv[0] = "/usr/bin/wc";
argv[1] = NULL;
pids[2] = add_child_process(argv, in, 1, envp);
close(in);
/** Wait for all process end to catch all return codes **/
int return_code;
waitpid(pids[0], &return_code, 0);
printf("Process 0 return : %d\n", return_code);
waitpid(pids[1], &return_code, 0);
printf("Process 1 return : %d\n", return_code);
waitpid(pids[2], &return_code, 0);
printf("Process 2 return : %d\n", return_code);
}
abort()
没有触发;所有执行的命令(在尝试 运行 代码之前,我确实检查过它们是否在您列出的目录中)。
我在 Mac 运行ning macOS Sierra 10.12.4 上使用 GCC 6.3.0 和命令行进行编译:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes -Wold-style-definition pc67.c -o pc67
$
这样,我得到了输出:
$ ./pc67
2 11 70
Process 0 return : 0
Process 1 return : 0
Process 2 return : 0
$
11个字是'total'和块数,然后ls -l
输出一行9个字。我已经重新运行 检查命令前后ps
的输出;没有杂散进程 运行ning.
方案二——规避不治本
Thanks, but unlike Bash echo "ping google.com | head -2 | wc" | bash
, it is still blocked in a wait and doesn't terminate the program.
我不清楚您的替代命令行与您的问题有什么关系。但是,当您引入 ping google.com
而不是 ls -l
作为命令时,可能会发生许多事情。您不能像那样合法地更改问题的参数。这完全是一个新问题。
在 shell 代理项中,您没有指定程序的路径;你的代码不会处理那个。 (如果您使用 execvp()
而不是 execve()
— 当您只是简单地中继继承的环境时使用 execve()
是没有意义的;无论如何环境都是继承的 — 那么命令的路径将是无关紧要的).
但是,使用 "/sbin/ping"
和 "google.com"
(在程序 pc23.c
的副本中)似乎挂起。从另一个终端查看设置,我看到:
$ ps -ftttys000
UID PID PPID C STIME TTY TIME CMD
0 51551 51550 0 10:13AM ttys000 0:00.50 login -pf jleffler
502 51553 51551 0 10:13AM ttys000 0:00.14 -bash
502 54866 51553 0 11:10AM ttys000 0:00.01 pc23
502 54867 54866 0 11:10AM ttys000 0:00.00 /sbin/ping google.com
502 54868 54866 0 11:10AM ttys000 0:00.00 (head)
502 54869 54866 0 11:10AM ttys000 0:00.00 (wc)
$
head
和 wc
进程都已终止(这些是僵尸的条目),但 ping
进程并未死亡。好像没什么大用,但也没死。
一段时间后,我得到:
$ ps -ftttys000
UID PID PPID C STIME TTY TIME CMD
0 51551 51550 0 10:13AM ttys000 0:00.50 login -pf jleffler
502 51553 51551 0 10:13AM ttys000 0:00.14 -bash
502 54866 51553 0 11:10AM ttys000 0:00.01 pc23
502 54867 54866 0 11:10AM ttys000 0:00.09 /sbin/ping google.com
502 54868 54866 0 11:10AM ttys000 0:00.00 (head)
502 54869 54866 0 11:10AM ttys000 0:00.00 (wc)
$
它设法使用了 9 CPU 秒。因此,在这种情况下,出于某种原因,ping
没有关注 SIGPIPE
信号。
如何解决?这需要实验,而且可能更复杂。最简单的解决方法是添加诸如 -c
和 3
之类的选项——这对我很有用。我没有立即去寻找替代修复的动力。
ping
的 macOS 手册页部分说:
-c count
Stop after sending (and receiving) count ECHO_RESPONSE packets. If this option is not specified, ping
will operate until interrupted. If this option is specified in conjunction with ping
sweeps, each sweep will consist of count packets.
推测 'interrupted' 一词的精确度很有趣。如果发送了实际的 (Control-C) 中断或 SIGTERM
信号 (kill 54867
),程序将终止。奇怪的是,它有时会在 SIGPIPE
上停止,有时不会。
第三种解决方案——关闭文件描述符
进一步思考,问题是代码没有关闭足够的文件描述符。这通常是管道未终止的问题。将 ls
作为第一个进程,问题就隐藏起来了,因为 ls
自动终止,关闭杂散的文件描述符。
更改为 ping
会暴露问题。这是代码的另一个修订版。它关闭了 dup2()
描述符(哎呀;打自己的手腕)。它还确保通过 add_child_process()
的新 tbc
(待关闭)文件描述符参数关闭其他管道描述符。我还选择使用 execv()
而不是 execve()
,从 add_child_process()
函数中删除一个参数,并允许 int main(void)
因为程序不注意它的参数(允许我丢失 assert()
,这是 'ensure',参数计数和向量参数是 'used',只要你没有使用 -DNDEBUG
或等价物进行编译).
我还调整了命令构建代码,以便 add/remove 来自 ping
的 -c
和 3
参数或 add/remove 来自其他命令的参数。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
static
int add_child_process(char **argv, int in, int out, int tbc)
{
int pid;
pid = fork();
if (pid == 0)
{
if (tbc >= 0)
close(tbc);
if (in != 0)
{
dup2(in, 0);
close(in);
}
if (out != 1)
{
dup2(out, 1);
close(out);
}
execv(argv[0], argv);
abort();
}
return pid;
}
int main(void)
{
int in;
int pipes[2];
char *argv[10];
int pids[3];
/** Launch first process that read on original stdin (0) and write on out of pipe **/
pipe(pipes);
int argn = 0;
argv[argn++] = "/sbin/ping";
//argv[argn++] = "-c";
//argv[argn++] = "3";
argv[argn++] = "google.com";
argv[argn++] = NULL;
pids[0] = add_child_process(argv, 0, pipes[1], pipes[0]);
close(pipes[1]);
in = pipes[0];
/** Launch second process that read on in of old pipe and write on out of new pipe **/
pipe(pipes);
argn = 0;
argv[argn++] = "/usr/bin/head";
argv[argn++] = "-2";
argv[argn++] = NULL;
pids[1] = add_child_process(argv, in, pipes[1], pipes[0]);
close(in);
close(pipes[1]);
in = pipes[0];
/** Launch last process that read on in of old pipe and write on original stdout (1) **/
argn = 0;
argv[argn++] = "/usr/bin/wc";
argv[argn++] = NULL;
pids[2] = add_child_process(argv, in, 1, -1);
close(in);
/** Wait for all process end to catch all return codes **/
int return_code;
waitpid(pids[0], &return_code, 0);
printf("Process 0 return : %d\n", return_code);
waitpid(pids[1], &return_code, 0);
printf("Process 1 return : %d\n", return_code);
waitpid(pids[2], &return_code, 0);
printf("Process 2 return : %d\n", return_code);
}
使用此代码(从 pc73.c
构建的可执行文件 pc73
),我得到如下输出:
$ ./pc73
2 14 109
Process 0 return : 13
Process 1 return : 0
Process 2 return : 0
$
wc
的输出与另一个输出之间有短暂的亚秒级停顿; ping
命令在尝试再次写入之前等待一秒钟。 13
的退出状态表明 ping
确实死于 SIGPIPE
信号。之前的问题是 ping
仍然打开了管道的读取端,所以它没有得到 SIGPIPE
信号。
要吸取的教训——关闭大量文件描述符
使用管道时,确保关闭所有需要关闭的文件描述符。
我想使用 execve、dup2、[=38= 在 C 中重现 UNIX Shell 的管道系统]fork、waitpid & pipe 函数。
对,例如这个命令:/bin/ls -l | /usr/bin/head -2 | /usr/bin/wc
被转载为:
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int add_child_process(char **argv, int in, int out, char **envp)
{
int pid;
pid = fork();
if (pid == 0)
{
if (in != 0)
{
dup2(in, 0);
}
if (out != 1)
{
dup2(out, 1);
}
if (execve(argv[0], argv, envp) == -1)
perror("Execve failed");
}
else
return (pid);
}
int main(int av, char **ag, char **envp)
{
int in;
int pipes[2];
char *argv[3];
int pids[3];
/** Launch first process that read on original stdin (0) and write on out of pipe **/
pipe(pipes);
argv[0] = "/bin/ls";
argv[1] = "-l";
argv[2] = NULL;
pids[0] = add_child_process(argv, 0, pipes[1], envp);
close(pipes[1]);
in = pipes[0];
/** Launch second process that read on in of old pipe and write on out of new pipe **/
pipe(pipes);
argv[0] = "/usr/bin/head";
argv[1] = "-2";
argv[2] = NULL;
pids[1] = add_child_process(argv, in, pipes[1], envp);
close(in);
close(pipes[1]);
in = pipes[0];
/** Launch last process that read on in of old pipe and write on original stdout (1) **/
argv[0] = "/usr/bin/wc";
argv[1] = NULL;
pids[2] = add_child_process(argv, in, 1, envp);
close(in);
/** Wait for all process end to catch all return codes **/
int return_code;
waitpid(pids[0], &return_code, 0);
printf("Process 0 return : %d\n", return_code);
waitpid(pids[1], &return_code, 0);
printf("Process 1 return : %d\n", return_code);
waitpid(pids[2], &return_code, 0);
printf("Process 2 return : %d\n", return_code);
}
工作,输出为:
2 11 60
Process 0 return : 0
Process 1 return : 0
Process 2 return : 0
喜欢echo "/bin/ls -l | /usr/bin/head -2 | /usr/bin/wc" | bash
但对于像 ping google.com | head -2 | wc
这样的阻塞命令,它显示为:
2 16 145
并保持封锁状态。
这是使用此命令更新的主要内容:
int main(int av, char **ag, char **envp)
{
int in;
int pipes[2];
char *argv[3];
int pids[3];
/** Launch first process that read on original in (0) and write on out of pipe **/
pipe(pipes);
argv[0] = "/bin/ping";
argv[1] = "google.com";
argv[2] = NULL;
pids[0] = add_child_process(argv, 0, pipes[1], envp);
close(pipes[1]);
in = pipes[0];
/** Launch second process that read on in of old pipe and write on out of new pipe **/
pipe(pipes);
argv[0] = "/usr/bin/head";
argv[1] = "-2";
argv[2] = NULL;
pids[1] = add_child_process(argv, in, pipes[1], envp);
close(in);
close(pipes[1]);
in = pipes[0];
/** Launch last process that read on in of old pipe and write on original stdout (1) **/
argv[0] = "/usr/bin/wc";
argv[1] = NULL;
pids[2] = add_child_process(argv, in, 1, envp);
close(in);
/** Wait for all process end to catch all return codes **/
int return_code;
waitpid(pids[0], &return_code, 0);
printf("Process 0 return : %d\n", return_code);
waitpid(pids[1], &return_code, 0);
printf("Process 1 return : %d\n", return_code);
waitpid(pids[2], &return_code, 0);
printf("Process 2 return : %d\n", return_code);
}
我真的不明白为什么会出现这种行为,例如在 Bash 中:echo "ping google.com | head -2 | wc" | bash
显示 2 16 145
而不是卡住。
如何处理阻塞命令?我需要根据最后一个错误代码获取我的进程的所有 return 代码,以便 return return。
您的 add_child_process()
函数应该 return PID;它没有。它还应该在 execve()
之后进行错误处理,以防程序无法执行。
第一个解决方案——不够好
有了这些修复(以及其他各种更改以超过我的最低编译警告级别——例如 #include <stdio.h>
以便在使用之前有一个 printf()
的声明),我大致得到预期的输出。
我用这段代码(源文件pc67.c
)来测试:
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
static
int add_child_process(char **argv, int in, int out, char **envp)
{
int pid;
pid = fork();
if (pid == 0)
{
if (in != 0)
{
dup2(in, 0);
}
if (out != 1)
{
dup2(out, 1);
}
execve(argv[0], argv, envp);
abort();
}
return pid;
}
int main(int av, char **ag, char **envp)
{
int in;
int pipes[2];
char *argv[3];
int pids[3];
assert(ag[av] == 0);
/** Launch first process that read on original stdin (0) and write on out of pipe **/
pipe(pipes);
argv[0] = "/bin/ls";
argv[1] = "-l";
argv[2] = NULL;
pids[0] = add_child_process(argv, 0, pipes[1], envp);
close(pipes[1]);
in = pipes[0];
/** Launch second process that read on in of old pipe and write on out of new pipe **/
pipe(pipes);
argv[0] = "/usr/bin/head";
argv[1] = "-2";
argv[2] = NULL;
pids[1] = add_child_process(argv, in, pipes[1], envp);
close(in);
close(pipes[1]);
in = pipes[0];
/** Launch last process that read on in of old pipe and write on original stdout (1) **/
argv[0] = "/usr/bin/wc";
argv[1] = NULL;
pids[2] = add_child_process(argv, in, 1, envp);
close(in);
/** Wait for all process end to catch all return codes **/
int return_code;
waitpid(pids[0], &return_code, 0);
printf("Process 0 return : %d\n", return_code);
waitpid(pids[1], &return_code, 0);
printf("Process 1 return : %d\n", return_code);
waitpid(pids[2], &return_code, 0);
printf("Process 2 return : %d\n", return_code);
}
abort()
没有触发;所有执行的命令(在尝试 运行 代码之前,我确实检查过它们是否在您列出的目录中)。
我在 Mac 运行ning macOS Sierra 10.12.4 上使用 GCC 6.3.0 和命令行进行编译:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes -Wold-style-definition pc67.c -o pc67
$
这样,我得到了输出:
$ ./pc67
2 11 70
Process 0 return : 0
Process 1 return : 0
Process 2 return : 0
$
11个字是'total'和块数,然后ls -l
输出一行9个字。我已经重新运行 检查命令前后ps
的输出;没有杂散进程 运行ning.
方案二——规避不治本
Thanks, but unlike Bash
echo "ping google.com | head -2 | wc" | bash
, it is still blocked in a wait and doesn't terminate the program.
我不清楚您的替代命令行与您的问题有什么关系。但是,当您引入 ping google.com
而不是 ls -l
作为命令时,可能会发生许多事情。您不能像那样合法地更改问题的参数。这完全是一个新问题。
在 shell 代理项中,您没有指定程序的路径;你的代码不会处理那个。 (如果您使用 execvp()
而不是 execve()
— 当您只是简单地中继继承的环境时使用 execve()
是没有意义的;无论如何环境都是继承的 — 那么命令的路径将是无关紧要的).
但是,使用 "/sbin/ping"
和 "google.com"
(在程序 pc23.c
的副本中)似乎挂起。从另一个终端查看设置,我看到:
$ ps -ftttys000
UID PID PPID C STIME TTY TIME CMD
0 51551 51550 0 10:13AM ttys000 0:00.50 login -pf jleffler
502 51553 51551 0 10:13AM ttys000 0:00.14 -bash
502 54866 51553 0 11:10AM ttys000 0:00.01 pc23
502 54867 54866 0 11:10AM ttys000 0:00.00 /sbin/ping google.com
502 54868 54866 0 11:10AM ttys000 0:00.00 (head)
502 54869 54866 0 11:10AM ttys000 0:00.00 (wc)
$
head
和 wc
进程都已终止(这些是僵尸的条目),但 ping
进程并未死亡。好像没什么大用,但也没死。
一段时间后,我得到:
$ ps -ftttys000
UID PID PPID C STIME TTY TIME CMD
0 51551 51550 0 10:13AM ttys000 0:00.50 login -pf jleffler
502 51553 51551 0 10:13AM ttys000 0:00.14 -bash
502 54866 51553 0 11:10AM ttys000 0:00.01 pc23
502 54867 54866 0 11:10AM ttys000 0:00.09 /sbin/ping google.com
502 54868 54866 0 11:10AM ttys000 0:00.00 (head)
502 54869 54866 0 11:10AM ttys000 0:00.00 (wc)
$
它设法使用了 9 CPU 秒。因此,在这种情况下,出于某种原因,ping
没有关注 SIGPIPE
信号。
如何解决?这需要实验,而且可能更复杂。最简单的解决方法是添加诸如 -c
和 3
之类的选项——这对我很有用。我没有立即去寻找替代修复的动力。
ping
的 macOS 手册页部分说:
-c count
Stop after sending (and receiving) count ECHO_RESPONSE packets. If this option is not specified,
ping
will operate until interrupted. If this option is specified in conjunction withping
sweeps, each sweep will consist of count packets.
推测 'interrupted' 一词的精确度很有趣。如果发送了实际的 (Control-C) 中断或 SIGTERM
信号 (kill 54867
),程序将终止。奇怪的是,它有时会在 SIGPIPE
上停止,有时不会。
第三种解决方案——关闭文件描述符
进一步思考,问题是代码没有关闭足够的文件描述符。这通常是管道未终止的问题。将 ls
作为第一个进程,问题就隐藏起来了,因为 ls
自动终止,关闭杂散的文件描述符。
更改为 ping
会暴露问题。这是代码的另一个修订版。它关闭了 dup2()
描述符(哎呀;打自己的手腕)。它还确保通过 add_child_process()
的新 tbc
(待关闭)文件描述符参数关闭其他管道描述符。我还选择使用 execv()
而不是 execve()
,从 add_child_process()
函数中删除一个参数,并允许 int main(void)
因为程序不注意它的参数(允许我丢失 assert()
,这是 'ensure',参数计数和向量参数是 'used',只要你没有使用 -DNDEBUG
或等价物进行编译).
我还调整了命令构建代码,以便 add/remove 来自 ping
的 -c
和 3
参数或 add/remove 来自其他命令的参数。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
static
int add_child_process(char **argv, int in, int out, int tbc)
{
int pid;
pid = fork();
if (pid == 0)
{
if (tbc >= 0)
close(tbc);
if (in != 0)
{
dup2(in, 0);
close(in);
}
if (out != 1)
{
dup2(out, 1);
close(out);
}
execv(argv[0], argv);
abort();
}
return pid;
}
int main(void)
{
int in;
int pipes[2];
char *argv[10];
int pids[3];
/** Launch first process that read on original stdin (0) and write on out of pipe **/
pipe(pipes);
int argn = 0;
argv[argn++] = "/sbin/ping";
//argv[argn++] = "-c";
//argv[argn++] = "3";
argv[argn++] = "google.com";
argv[argn++] = NULL;
pids[0] = add_child_process(argv, 0, pipes[1], pipes[0]);
close(pipes[1]);
in = pipes[0];
/** Launch second process that read on in of old pipe and write on out of new pipe **/
pipe(pipes);
argn = 0;
argv[argn++] = "/usr/bin/head";
argv[argn++] = "-2";
argv[argn++] = NULL;
pids[1] = add_child_process(argv, in, pipes[1], pipes[0]);
close(in);
close(pipes[1]);
in = pipes[0];
/** Launch last process that read on in of old pipe and write on original stdout (1) **/
argn = 0;
argv[argn++] = "/usr/bin/wc";
argv[argn++] = NULL;
pids[2] = add_child_process(argv, in, 1, -1);
close(in);
/** Wait for all process end to catch all return codes **/
int return_code;
waitpid(pids[0], &return_code, 0);
printf("Process 0 return : %d\n", return_code);
waitpid(pids[1], &return_code, 0);
printf("Process 1 return : %d\n", return_code);
waitpid(pids[2], &return_code, 0);
printf("Process 2 return : %d\n", return_code);
}
使用此代码(从 pc73.c
构建的可执行文件 pc73
),我得到如下输出:
$ ./pc73
2 14 109
Process 0 return : 13
Process 1 return : 0
Process 2 return : 0
$
wc
的输出与另一个输出之间有短暂的亚秒级停顿; ping
命令在尝试再次写入之前等待一秒钟。 13
的退出状态表明 ping
确实死于 SIGPIPE
信号。之前的问题是 ping
仍然打开了管道的读取端,所以它没有得到 SIGPIPE
信号。
要吸取的教训——关闭大量文件描述符
使用管道时,确保关闭所有需要关闭的文件描述符。