【发布时间】:2019-01-04 01:50:40
【问题描述】:
我有两个程序通过命名管道进行通信(在 Mac 上),但命名管道的缓冲区大小太小。程序 1 在读取管道 2 之前将 50K 字节写入管道 1。命名管道为 8K(在我的系统上),因此程序 1 阻塞,直到数据被消耗。程序 2 从管道 1 读取 20K 字节,然后将 20K 字节写入管道 2。 Pipe2 不能容纳 20K 所以程序 2 现在阻塞。只有在程序 1 进行读取时才会释放它。但是程序1被阻塞等待程序2。死锁
我想我可以通过创建一个垫圈程序来解决这个问题,该程序读取标准输入非阻塞并写入标准输出非阻塞,将数据临时存储在一个大缓冲区中。我使用 cat data 测试了程序 | ./垫片 0 | ./gasket 1 > out,期望 out 是数据的副本。然而,虽然垫片的第一次调用按预期工作,但第二个程序中的读取在所有数据被消耗之前返回 0,并且在后续调用中永远不会返回 0 以外的任何内容。
我在 MAC 和 Linux 上都尝试了下面的代码。两者的行为相同。我添加了日志记录,以便我可以看到第二次调用垫片的 fread 开始没有数据,即使它没有读取第一次调用写入的所有数据。
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFFER_SIZE 100000
char buffer[BUFFER_SIZE];
int elements=0;
int main(int argc, char **argv)
{
int total_read=0, total_write=0;
FILE *logfile=fopen(argv[1],"w");
int flags = fcntl(fileno(stdin), F_GETFL, 0);
fcntl(fileno(stdin), F_SETFL, flags | O_NONBLOCK);
flags = fcntl(fileno(stdout), F_GETFL, 0);
fcntl(fileno(stdout), F_SETFL, flags | O_NONBLOCK);
while (1) {
int num_read=0;
if (elements < (BUFFER_SIZE-1024)) { // space in buffer
num_read = fread(&buffer[elements], sizeof(char), 1024, stdin);
elements += num_read;
total_read += num_read;
fprintf(logfile,"read %d (%d) elements \n",num_read, total_read); fflush(logfile);
}
if (elements > 0) { // something in buffer that we can write
int num_written = fwrite(&buffer[0],sizeof(char),elements, stdout); fflush(stdout);
total_write += num_written;
fprintf(logfile,"wrote %d (%d) elements \n",num_written, total_write); fflush(logfile);
if (num_written > 0) { // copy data to top of buffer
for (int i=0; i<(elements-num_written); i++) {
buffer[i] = buffer[i+num_written];
}
elements -= num_written;
}
}
}
}
我想我可以让垫片成为多线程,并在一个线程中使用阻塞读取并在另一个线程中使用阻塞写入,但我想了解为什么非阻塞 IO 似乎对我不利。
谢谢!
【问题讨论】:
-
你好 Dror。 “命名管道的缓冲区大小太小”如何?换句话说,它没有做什么你想让它做的事情?
-
嗨。我有两个程序通过两个命名管道相互通信。程序 1 在读取管道 2 之前将 50K 字节写入管道 1。命名管道为 8K,因此程序 1 阻塞,直到数据被消耗。程序 2 从管道 1 读取 20K 字节,然后将 20K 字节写入管道 2。 Pipe2 不能容纳 20K 所以程序 2 现在阻塞。只有在程序 1 进行读取时才会释放它。但是程序1被阻塞等待程序2。死锁
-
好的 Dror,我的建议是修改你的问题来解释这一点,我会给你一个答案。
-
好的,问题已修正。谢谢!
标签: nonblocking stdio