【发布时间】:2012-04-12 06:43:27
【问题描述】:
我见过的工作队列的正常实现涉及互斥锁和条件变量。
消费者:
A) Acquires Lock
B) While Queue empty
Wait on Condition Variable (thus suspending thread and releasing lock)
C) Work object retrieved from queue
D) Lock is released
E) Do Work
F) GOTO A
制作人:
A) Acquires Lock
B) Work is added to queue
C) condition variable is signaled (potentially releasing worker)
D) Lock is released
我一直在浏览一些代码,并且看到了一个使用 POSIX 管道的实现(我以前没有见过这种技术)。
消费者:
A) Do select on pipe (thus suspending thread while no work)
B) Get Job from pipe
C) Do Work
D) GOTO A
制作人:
A) Write Job to pipe.
由于生产者和消费者是同一个应用程序中的线程(因此它们共享相同的地址空间,因此它们之间的指针是有效的);作业作为工作对象(C++ 对象)的地址写入管道。因此,必须从管道中写入/读取的只是一个 8 字节地址。
我的问题是:
- 这是一种常见的技术吗(我是否已经避开了这个),有哪些优点/缺点?
我的好奇心被激起了,因为管道技术不涉及任何可见的锁定或信号(它可能隐藏在选择中)。所以我想知道这是否会更有效率?
编辑:
基于@Maxim Yegorushkin 回答中的 cmets。
实际上,此场景中的“生产者”参与了来自大量源的大量并行 IO。所以我怀疑原作者虽然很希望这个线程在任何情况下都不会被阻塞,但也不想在“Producer”线程中付出高昂的代价。
【问题讨论】:
-
其实在管道的情况下,可以跳过A。如果您在
select()中阻塞单个文件描述符,您也可以调用read()并在那里阻塞。 -
@Rob。实际上有两个管道,因为消费者将响应对象写入另一个管道(对于生产者)。所以它会选择;在输入管道上读取并可能在输出管道上写入(假设我们已经排队等待外出)。
-
这是否仅适用于低于内核管道大小的有效负载大小?根据架构,这可能是 512 字节、4k、16k 等。超过此大小的有效负载可能跨越多个不同的消费者?
-
@Xepoch:有效载荷(用于管道)为 8 个字节(或指针的大小)。由于生产者和消费者都是同一进程中的线程,因此代码通过管道传递指针,而实际数据位于动态分配的 C++ 对象中。
-
@loki,正确,但这只是因为内核将允许一些最大的“缓冲区”以原子/串行方式进入管道(可能在上下文切换之前)。重点是让你的有效载荷保持在低水平。
标签: c++ message-queue pipe