【问题标题】:equivalent of select for pipes on windows相当于在 windows 上选择管道
【发布时间】:2016-07-09 00:39:57
【问题描述】:

我需要阻塞直到我的一个管道有数据要读取。

我已经尝试过 WaitForMultipleObjects 但它只是立即返回说其中一个管道有数据。管道块上的后续 ReadFile。

我不能使用 PeekNamedPipe,因为我需要阻塞直到数据可用,并且在睡眠循环中窥视会因为睡眠而导致延迟反应。

此代码是跨平台的,并且在 linux 上一切正常,因为我可以在一组 fifo fd 上使用 Select,然后在 select 返回时从准备好的那个中读取,但是似乎没有任何等效的窗户。

我看到很多人说你必须在读/写时使用重叠操作,但这不是需要我循环并尝试读取每个管道吗?

是否没有单个阻塞操作会阻塞直到其中一个管道中有数据?

【问题讨论】:

  • “我已经尝试过 WaitForMultipleObjects” - 如果您认为您为解决您的问题而编写的代码是相关的,那么您是对的。它属于问题,被简化为最小但理想的完整示例,尽可能重现您的问题。据我们所知,您错误地使用了 WaitForMultipleObjects,并且没有发布任何代码来反驳该假设。是的,重叠或 iocp 是我可能会这样做的方式。
  • @EJP 天哪! 1993年不是火发明之前吗?
  • 更严肃的一点是:WaitForSingleObject 返回WAIT_OBJECT_0 + n,其中n 是发出信号的数组索引的索引。我的猜测是因为文档中明确说明了这一点,您实际上并没有检查返回值,而对WaitForSingleObject 的调用实际上是返回WAIT_FAILED。 (当然,这在业务中被称为有根据的猜测,因为您没有向我们展示您实际在做什么。您可能编写了正确检查返回值并出色处理错误的代码。)跨度>
  • 我现在无法发布代码,因为它正在工作,我现在回家了,尽管我确实正确处理了返回值,因为这就是我确定发出信号的句柄的方式。问题是 WaitForMultipleObjects 在管道中没有任何内容时立即返回。 MSDN 状态:“请注意,WAIT_OBJECT_0 定义为 0”。之后执行的代码是 (rv - WAIT_OBJECT_0) == 0 的结果,所以从我看到的情况来看,它向我发出信号表明第 0 个句柄已准备好 - 然后随后的 ReadFile 被阻止。
  • 如果您阅读了WaitForMultipleObjects() 的文档,管道不是支持它等待的对象类型。确保返回值实际上在WAIT_OBJECT_0 - WAIT_OBJECT_0+n 的范围内,然后再减去WAIT_OBJECT_0 得到索引。

标签: c++ winapi pipe


【解决方案1】:

我已经尝试过 WaitForMultipleObjects 但它只是立即返回说其中一个管道有数据。管道块上的后续 ReadFile。

MSDN 的可等待对象类型列表中没有提到管道,因此您不能将管道传递给任何WaitFor...() 系列函数。

我看到很多人说你必须在读/写时使用重叠操作,但这不是需要我循环并尝试读取每个管道吗?

重叠 I/O 是解决问题的方法。

以重叠模式创建管道。然后你可以:

  1. 通过CreateEvent() 创建一个事件对象并将其分配给您用于给定读取操作的OVERLAPPED 结构。然后,您可以在多个管道上发出异步ReadFile/Ex() 操作,并使用WaitForMultipleObject() 等待事件对象,直到其中一个发出信号。 WaitForMultipleObjects() 的返回值将告诉您发出了哪个事件,以及通过关联哪个管道读取了一些数据。

  2. 使用GetQueuedCompletionStatus/Ex()而不是WaitForMultipleObjects(),那么你可以省略事件对象。 GetQueuedCompletionStatus/Ex() 将告诉您哪些特定的 OVERLAPPED 结构已完成(如果需要,您可以使用 hEvent 字段传递用户定义的数据)。

这在 MSDN 文档中有介绍:

Synchronous and Overlapped Pipe I/O

select() 可以在一次调用中报告多个已完成的操作。但是,WaitForMultipleObjects()GetQueuedCompletionStatus() 一次只能报告一个已完成的操作。您必须循环调用它们以发现多个操作是否已完成。另一方面,GetQueuedCompletionStatusEx() 可以一次报告多个已完成的操作。

是否没有单个阻塞操作会阻塞直到其中一个管道中有数据?

是的。见上文。

【讨论】:

  • 太棒了,比那些说我可能错误地处理 WaitForMultipleObjects 的返回值的 cmets 好多了。这肯定会很痛苦,因为我最初包装了​​ POSIX 和 windows 管道并且没有提供任何使用重叠的方法。为了完成这项工作,我将不得不返回并进行更改。不过再次感谢您!
【解决方案2】:

是的,使用重叠 I/O 是最佳选择。您可以将每个管道句柄绑定到一个 I/O 完成端口(直接通过CreateIoCompletionPort(),或间接通过BindIoCompletionCallback())。对于异步读取,创建一个从OVERLAPPED 继承的结构,并使用管道句柄将其传递给ReadFile/Ex()。每次读取都需要自己分配的该结构实例。然后您可以使用GetQueuedCompletionStatus()(或绑定的回调)来检测每次读取何时完成。您不需要任何循环。

【讨论】:

  • 我试图修正这里的语法,但最后一个“句子”没有意义。如果您要回答,尤其是像这样的问题,请在提交之前校对您的答案。 (对于像这样的问题,并且在一般的 WinAPI 标签中,你不必是西方最快的枪,只要你校对你的答案并且相当完整。)
猜你喜欢
  • 2013-10-08
  • 1970-01-01
  • 2014-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-25
  • 1970-01-01
相关资源
最近更新 更多