我在处理涉及实施管理进程间通信的程序的作业时遇到问题。
简化上下文: 有一个管道,我们称之为 A,和 16 个进程,编号从 0 到 15。
在管道 A 中,已经有 2*512 = 1024 字节的消息。 进程 0 需要读取这 1024 字节的消息然后退出,而进程 1 到 15(含)则应该向管道 A 写入 512 字节的零。 由于某种原因,最后一个写入管道 A 的进程挂起写入操作。进程执行任务的顺序是任意的。
在我的系统中,管道容量为65536,确认使用:
int fd[2];
pipe(fd);
void* message = malloc(512);
for (int i = 0; i < 128; i++) {
write(fd[1], message, 512);
}
free(message);
int nbytes = 0;
if (ioctl(fd[1], FIONREAD, &nbytes) >= 0) {
printf("There are %d bytes in the pipe\n", nbytes);
}
输出:管道中有 65536 个字节。
在每次写入管道 A 之前,我都会打印其中已有多少字节。我知道理论上每个进程都可以打印管道大小为零,然后写入管道,但即使每个后续打印的管道大小都大于前一个,问题仍然存在。
这是1到15每个进程执行的代码:
int pipe_size = 0;
if (ioctl(PIPE_A_DESCRIPTOR, FIONREAD, &pipe_size) >= 0) {
printf("check_1, process %d, there are %d bytes in the pipe %d\n", get_process_num(), pipe_size);
}
write(PIPE_A_DESCRIPTOR, message, 512);
printf("check_2, process %d\n", get_process_num());
fflush(stdout);
进程 0 使用
读取数据for (int i = 0; i < 2; i++) {
read(PIPE_A_DESCRIPTOR, buffer, 512);
}
部分输出:
check_1, process 1, there are 3584 bytes in the pipe
check_2, process 1
check_1, process 3, there are 4096 bytes in the pipe
check_2, process 3
check_1, process 7, there are 4608 bytes in the pipe
check_2, process 7
check_1, process 8, there are 5120 bytes in the pipe
check_2, process 8
check_1, process 14, there are 5632 bytes in the pipe
check_2, process 14
check_1, process 10, there are 6144 bytes in the pipe
check_2, process 10
check_1, process 15, there are 6656 bytes in the pipe
check_2, process 15
check_1, process 12, there are 7168 bytes in the pipe
check_1, process 13, there are 7168 bytes in the pipe
check_2, process 12
check_2, process 13
check_1, process 11, there are 8192 bytes in the pipe
0 read first 512 bytes
0 read second 512 bytes
如图所示,最后一个“check_2”丢失,进程卡在写操作上。
在整个程序中,我最多向管道 A 写入 18 条长度为 512 的消息,因此即使没有读取任何消息,管道也不应该已满。 即使由于某种原因 8192 是最大管道大小,进程 0 也应该从管道 A 读取 1024 字节,并且休眠进程应该被唤醒。
这个问题背后的原因可能是什么?除了满水的情况外,还有其他情况会导致管道堵塞吗? 我不提供完整的代码。首先,因为这是一个作业,其次,它的长度将超过 300 行。
非常感谢。
我不提供完整的代码。首先,因为这是一个作业,其次,它的长度将超过 300 行。
这很不幸,因为 300 行完全在限制之内。而且,可能导致程序出错的大部分原因都在您没有显示的代码中。
特别是
fork
相对于pipe
的位置。还有各种close
电话。
我必须推测一下你的代码在做什么。而且,我必须做最坏的打算。
所以,这只能是部分解决方案......
write
的返回值。管道可以返回“短”读取或写入。 (例如)您可以写入 128 个字节,但 write
返回 64。对于 read
也是如此。ioctl(fd[1], FIONREAD, &nbytes)
。我不太确定,但我认为这是无效的,因为 fd[1]
用于写作。fd[0]
上执行此操作。fd[0]
之前循环。fd[1]
after循环。fd[1]
之前循环。