【发布时间】:2018-01-31 14:47:57
【问题描述】:
我正在尝试编写一个包含两个进程的程序:
一个进程产生一些 a + b 问题并将其打印到其标准输出(如printf("%d %d\n", a, b)),并通过标准输入从另一个进程获取答案,并将答案记录到 log.txt。当所有的问题都被问到时,进程会打印出“-1 -1”来表示问题的结束。
另一个进程通过标准输入接收 a + b 问题(如scanf("%d%d", &a, &b)),并将答案打印到其标准输出。当a = b = -1 进程退出时。
我使用两对管道来连接两个进程。我使用dup2 将管道与标准输入和标准输出绑定。我的源代码如下所示:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/types.h>
// Get a + b question through stdin, and print answer to stdout
void calc_a_plus_b() {
int a, b;
while (scanf("%d%d", &a, &b) > 0)
{
if (a == -1 && b == -1)
break;
printf("%d\n", a + b);
fflush(stdout);
}
}
// Ask a + b through stdout, and get answer through stdin
// Log answer to log.txt
void ask_a_plus_b() {
FILE* log = fopen("log.txt", "w");
int i, a, b, c;
for (i = 0; i < 3; i++) {
a = i; b = i + 1;
printf("%d %d\n", a, b);
fflush(stdout);
scanf("%d", &c);
fprintf(log, "%d\n", c);
}
printf("-1 -1\n");
fclose(log);
}
int main()
{
pid_t ask_pid, calc_pid, term_pid;
int ask_to_calc[2], calc_to_ask[2]; // Two pairs of pipe
int status;
// Create pipe
pipe(ask_to_calc); pipe(calc_to_ask);
// Create calculate process
calc_pid = fork();
if (calc_pid == 0) {
// Close useless pipe
close(ask_to_calc[1]);
close(calc_to_ask[0]);
// Bind pipe to stdin and stdout
dup2(ask_to_calc[0], 0);
dup2(calc_to_ask[1], 1);
close(ask_to_calc[0]);
close(calc_to_ask[1]);
calc_a_plus_b();
return 0;
}
// Create ask process
ask_pid = fork();
if (ask_pid == 0) {
// Close useless pipe
close(ask_to_calc[0]);
close(calc_to_ask[1]);
// Bind pipe to stdin and stdout
dup2(calc_to_ask[0], 0);
dup2(ask_to_calc[1], 1);
ask_a_plus_b();
return 0;
}
// Wait for children to exit
while ((term_pid = wait(&status)) > 0) {
if (WIFSTOPPED(status))
{
// If child stopped but hasn't exited, ignore
continue;
} else if (WIFSIGNALED(status)) {
// Child exited due to signal
printf("%s terminated due to signal %d\n", ask_pid == term_pid ? "ask" : "calc", WTERMSIG(status));
} else {
// Child exited normally
printf("%s terminated normally\n", ask_pid == term_pid ? "ask" : "calc");
}
}
return 0;
}
这段代码运行正常,并打印出来
calc terminated normally
ask terminated normally
来自man 7 pipe (http://man7.org/linux/man-pages/man7/pipe.7.html) 我知道,当管道读取端的所有文件描述符都已关闭,而另一个进程仍在尝试写入该管道时,将发生 SIGPIPE。所以我决定把calc_a_plus_b中的所有代码都去掉,看看会发生什么。
令人惊讶的是,SIGPIPE 没有发生。程序只打印出来
calc terminated normally
之后程序就卡住了。我猜这是因为ask_a_plus_b 中的printf 被屏蔽了。
我想我已经关闭了管道ask_to_calc的读取端的所有文件描述符(我已经将管道绑定到计算进程的标准输入,但是进程已经退出,所以它的标准输入也被关闭了?),那么为什么当请求进程尝试写入管道时没有发生 SIGPIPE?
【问题讨论】:
-
请不要标记 c++ 和 c.您正在使用其中一个,因此请相应地标记。
-
与你的问题无关,但是
while (scanf("%d%d", &a, &b) > 0)->while (scanf("%d%d", &a, &b) == 2)或者你应该在进入循环之前初始化a和b。 -
两件事。 1. SIGPIPE 直到第二次写入封闭管道后才发送(第一次返回 0,第二次生成 SIGPIPE)。 2.你的父进程仍然打开管道。
-
你是对的......关闭父进程中的管道后,由于SIGPIPE,请求进程现在终止。抱歉弄错了,太尴尬了……-_-”