写入未满的管道会阻塞 C 中的进程

问题描述 投票:0回答:1

我在处理涉及实施管理进程间通信的程序的作业时遇到问题。

简化上下文: 有一个管道,我们称之为 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 行。

非常感谢。

c debugging pipe ipc blocking
1个回答
0
投票

我不提供完整的代码。首先,因为这是一个作业,其次,它的长度将超过 300 行。

这很不幸,因为 300 行完全在限制之内。而且,可能导致程序出错的大部分原因都在您没有显示的代码中。

特别是

fork
相对于
pipe
的位置。还有各种
close
电话。

我必须推测一下你的代码在做什么。而且,我必须做最坏的打算。

所以,这只能是部分解决方案......

  1. 没有检查
    write
    的返回值。管道可以返回“短”读取或写入。 (例如)您可以写入 128 个字节,但
    write
    返回 64。对于
    read
    也是如此。
  2. 你正在做
    ioctl(fd[1], FIONREAD, &nbytes)
    。我不太确定,但我认为这是无效的,因为
    fd[1]
    用于写作。
  3. 我会在接收器中的
    fd[0]
    上执行此操作。
  4. 在作者中,你没有关闭
    fd[0]
    之前循环。
  5. 在作者中,你没有关闭
    fd[1]
    after循环。
  6. 在阅读器中,您没有关闭
    fd[1]
    之前循环。
© www.soinside.com 2019 - 2024. All rights reserved.