设置管道缓冲区大小

18

我有一个使用posix管道实现多线程通信的C++应用程序(这样我就不必因死锁而疯狂了),

我将写操作设置为非阻塞,这样如果缓冲区没有足够的空间来写入数据,写程序将会得到一个错误。

if((pipe(pipe_des)) == -1)
    throw PipeException();

int flags = fcntl(pipe_des[1], F_GETFL, 0); // set write operation non-blocking
assert(flags != -1);
fcntl(pipe_des[1], F_SETFL, flags | O_NONBLOCK);

现在我希望将管道缓冲区大小设置为自定义值(在特定情况下是一个单词)。

我已经搜索过了,但是没有找到任何有用的信息。是否有一种方法(可能符合posix),可以实现这一点?

谢谢

Lorenzo

PS:我在Linux下(如果有用的话)


1
这是完全不适当使用assert()的情况,除非你的程序只在fcntl()永远没有错误的平台上运行。 - William Pursell
1
我认为你应该学习如何使用同步原语。使用管道会增加大约100倍的开销,而且似乎也无法实现你想要的功能。 - R.. GitHub STOP HELPING ICE
我知道如何使用同步原语 :) 实际上,我也有一个使用同步原语的版本... 从测试结果来看,使用管道的版本至少比同步版本更快(在某些情况下,管道更快...) - Zeruel
你可以使用Unix的socketpair代替管道。setsockopt(fd, SOL_SOCKET, SO_SNDBUF, size)是你想要设置缓冲区大小的调用。 - peterh
3个回答

20

既然你提到你正在使用Linux,而且可能不介意非可移植性,你可能会对文件描述符操作 F_SETPIPE_SZ 感兴趣,它自Linux 2.6.35以来可用。

int pipe_sz = fcntl(pipe_des[1], F_SETPIPE_SZ, sizeof(size_t));

在调用之后,您会发现pipe_sz == getpagesize(),因为缓冲区的大小不能小于系统页面大小。请参见fcntl(2)


4
我谷歌搜索了“linux管道缓冲区大小”,并获得了这个链接。基本上,管道的限制大小是64Kb,并且是硬编码的。 编辑 链接已失效,而且可能是错误的。Linux的pipe(7)手册页指出:

管道的容量是有限的。如果管道已满,则write(2)将会阻塞或失败,具体取决于是否设置了O_NONBLOCK标志(请参见下文)。不同的实现对管道容量有不同的限制。应用程序不应依赖特定的容量:一个应用程序应该被设计成读取进程尽快消耗所有可用数据,以便写入进程不会被阻塞。

在Linux 2.6.11之前的版本中,管道的容量与系统页面大小相同(例如,在i386上为4096字节)。自Linux 2.6.11以来,管道容量为16页(即,在页面大小为4096字节的系统中为65536字节)。自Linux 2.6.35以来,默认管道容量为16页,但是可以使用fcntl(2) F_GETPIPE_SZ和F_SETPIPE_SZ操作查询和设置容量。欲知详情,请参见fcntl(2)。

无论如何,我认为以下内容仍然适用:

我不确定为什么您要将限制设置得更低,这对我来说似乎是一个奇怪的想法。如果您希望编写者等待读者处理它所编写的内容,则应在另一个方向上使用管道来让读者发送回一个ack。


1
我正在通过管道发送任务。我想要的是,异步度可以通过传递给应用程序的参数进行配置。我认为将此行为合并到管道中而不跟踪其他信息和确认会是一种有效的解决方案... - Zeruel
底线是你不能按照你想要的方式去做。 - JeremyP
链接已失效。 - Volodymyr Boiko

2
您可以使用共享内存区域(类似于 System V)的两个字,一个用于发送数据,另一个用于接收数据,并使用它们实现管道。 其他解决方案,正如您之前可能发现的那样,涉及重新编译内核以按照您的意愿进行操作,但我想这并非您的情况。 Ciao!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接