exact
在上面的程序中,我有一个父级,使两个子进程属于同一父级。用户写入父进程,该进程通过管道传递要由子1或子2读取的消息。除非用户输入-1,否则它将持续进行此操作。
问题是我的switch语句中的情况没有执行,而是程序挂起。我认为我的管道在正确的地方关闭了。
答案 0 :(得分:0)
首先,您需要开始执行错误检查。检查您拨打的电话的手册页。在代码中添加检查以检测错误。当他们返回错误时,请使用perror
和exit(EXIT_FAILURE);
。
第二,您需要开始注意read
和write
返回的值,因为它们可能小于预期值。这些需要循环调用。
例如,对于read
,您将使用以下内容:
// Returns the number of bytes read.
// EOF was reached if the number of bytes read is less than requested.
// On error, returns -1 and sets errno.
ssize_t read_fixed_amount(int fd, char *buf, size_t size) {
if (size > SSIZE_MAX) {
errno = EINVAL;
return -1;
}
ssize_t bytes_read = 0;
while (size > 0) {
ssize_t rv = read(fd, buf, size);
if (rv <= 0)
return rv;
size -= rv;
bytes_read += rv;
buf += rv;
}
return bytes_read;
}
将使用类似这样的内容:
ssize_t bytes_read = read_fixed_amount(fd, buf, size);
if (bytes_read < 0) {
perror("read");
exit(EXIT_FAILURE);
}
if (bytes_read == 0) {
printf("EOF reached\n");
exit(EXIT_SUCCESS);
}
if (bytes_read != size) {
fprintf(stderr, "read: Premature EOF.\n");
exit(EXIT_FAILURE);
}
第三,只有在关闭管道写入端的所有文件描述符后,从管道读取的操作才会返回EOF。
在分叉之后,父母应该这样做
close(p1[0]);
close(p2[0]);
在叉子之后,孩子1应该做
close(p1[1]);
close(p2[0]);
close(p2[1]);
在叉子之后,孩子2应该做
close(p1[0]);
close(p1[1]);
close(p2[1]);
第四,这是怪物:
while (1) {
dup2(p1[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
...
close(p1[0]);
close(p1[1]);
}
真的吗?无限循环。尝试将STDIN重复设置为p1 [0]。复制封闭的描述符。
这应该出现在循环之前:
dup2(p1[0], STDIN_FILENO);
close(p1[0]);
或者您可以跳过这两个呼叫,而直接从p1[0]
而不是STDIN_FILENO
读取。
对于无限循环,它可以回到第二点。检查read
返回的值。
第五,您只等待一个孩子完成,但是有两个孩子要等待。您需要致电wait
两次。
答案 1 :(得分:0)
您需要向子进程发送一些信号,以通知然后终止,然后等待其退出。您应该定义一些预定义的消息,这意味着其终止子项的时间。检查以下代码。此处的预定义消息为"-1"
。您应该选择与应用程序的真实数据不冲突的自己的数据。
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define MSGSIZE 64
char msgbuf[MSGSIZE];
int main() {
int p1[2];
int p2[2];
int nread;
int choice = 0;
pid_t child_a, child_b;
if (pipe(p1) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
if (pipe(p2) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
child_a = fork();
if (child_a == 0) {
while (1) {
dup2(p1[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
printf("%d receives message: %s\n", getpid(), msgbuf);
close(p1[0]);
close(p1[1]);
if (strcmp(msgbuf, "-1") == 0) { // check if time to end
break;
}
}
} else {
child_b = fork();
if (child_b == 0) {
while (1) {
dup2(p2[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
printf("%d receives message: %s\n", getpid(), msgbuf);
close(p2[0]);
close(p2[1]);
if (strcmp(msgbuf, "-1") == 0) { // check if time to end
break;
}
}
} else {
while (1) {
printf("<child_to_receive_msg> <message>\n");
scanf("%d %s", &choice, msgbuf);
switch (choice) {
case 1:
usleep(250);
write(p1[1], msgbuf, MSGSIZE);
break;
case 2:
usleep(250);
write(p2[1], msgbuf, MSGSIZE);
break;
default:
printf("Process does not exist\n");
break;
case -1:
strcpy(msgbuf, "-1");
write(p1[1], msgbuf, MSGSIZE); // send message to end
close(p1[0]);
close(p2[0]);
printf("parent waiting\n");
wait(NULL);
exit(0);
}
}
}
}
return 0;
}