从命名管道并发选择

Posted

技术标签:

【中文标题】从命名管道并发选择【英文标题】:concurrent select from named pipe 【发布时间】:2013-09-10 03:50:54 【问题描述】:

假设我有一个从多个进程或线程多次打开的 fifo(命名管道)。它们都将调用 select() 进行并发读取。如果一个 writer 进来并写入,比如说一个字节到这个 fifo,所有阻塞的 select() 调用会同时返回,还是只会选择一个线程并从 select() 返回?

对此是否有任何规范,或者这是否取决于系统?

我问的原因是我想使用 fifos 实现类似 Windows 的手动重置事件。手动重置事件要求当事件发出信号时,所有等待的线程都将被释放(而不是自动重置事件只有一个)。

我可以为此使用 pthread conds,但我的要求是多个进程共享事件。

谢谢。

【问题讨论】:

【参考方案1】:

如果一个作家进来写,说一个字节到这个先进先出,所有 阻塞的 select() 调用同时返回或只有一个线程 被选中并从 select() 返回?

会有一个竞争条件。系统将开始以某种随机顺序唤醒线程,直到其中一个读取数据,清空缓冲区并阻止其他线程唤醒。

对此是否有任何规范,或者这是否取决于系统?

这取决于系统、应用程序布局、代码结构。这将是一种很棒的未定义行为。

我问的原因是我想使用 fifos 实现类似 Windows 的手动重置事件。

您是否在 Linux/Posix 上编码?使用 tee 函数而不是 read,使线程将一些状态代码写回管道以表示它们已唤醒。然后,通过在控制线程中读回数据来重置管道。

即,执行以下操作:

在工作线程中:选择(和阻止)。 在控制线程中:写入一个字节。现在选择没有阻塞。 工作线程被唤醒。现在在工作线程中做一个可选的 tee(一个字节)并将一个字节写回每个线程中的管道。 在控制线程中:读取和计数字节。如果所有工作线程波都唤醒,请再读取一个字节以擦除您写入的第一个字节。 select now 再次阻塞。

请注意,在完成整个过程之前,您不能再次输入 select。您可能需要两个这样的管道。

【讨论】:

非常感谢。所以你说所有线程都会从 select 中唤醒,但它可能不会立即发生,所以我们需要在这些唤醒之间重置事件时防止竞争条件。不幸的是,控制线程通常不知道有多少等待线程,所以我可能不得不做一些更复杂的事情,比如在选择“注册”等待线程之前写一个字节。我会考虑的。 我想我需要某种进程间 rwlock。然后每个线程,在执行 select() 之前会将其锁定为读取模式,然后在从 select 返回后将其解锁,它不需要从 fifo 读取任何内容。正在执行 ResetEvent 的线程只会将 rwlock 锁定在写模式并读回在 SetEvent 期间写入的字节,然后解锁 rwlock。这将强制控制线程等待,直到每个等待线程从 select 返回。所以只需要找到如何实现进程间rwlock。

以上是关于从命名管道并发选择的主要内容,如果未能解决你的问题,请参考以下文章

Windows 命名管道无法正确响应并发请求

Java中命名管道的并发读/写(在Windows上)

命名管道(C#)

说解在shell中通过mkfifo创建命名管道来控制多个进程并发执行

在命名管道上选择

带有命名管道的 WCF:如何允许并行调用?