在C/C++ Linux中等待多个信号量而不进行忙等待

6
如果我有多个信号量,如何让进程阻塞直到至少有一个信号量可用?我知道可以使用忙等待循环来实现,例如:
// blocks until one of the semaphores in sems is free, returns
// index of semaphore that was available
int multiple_sem_wait(sem_t **sems, int num_sems) {
   while (true) {
      for (int i = 0; i < num_sems; ++i) {
         if (sem_trywait(sems[i]) == 0) {
            return i;
         }
      }
   }
}

但是有没有一种方法可以在不使用繁忙循环的情况下实现这一点?也许还有其他的IPC技术,除了信号量,我应该使用哪些?

谢谢。


2
不妨使用条件变量,而不是使用信号量? - Jeff Mercado
2个回答

6

这里(developers.sun.com,通过Internet Archive)是Sun关于如何在Solaris中实现他们的WaitForMultipleObjects仿真的简短论文。基本思路是将一系列条件变量与句柄相关联(由互斥保护),并在句柄发出信号时同时发出所有条件变量的信号。每次调用仿真的WaitForMultipleObjects时,都会创建一个新的条件变量,并将其添加到您感兴趣的所有句柄列表中。在WaitForMultipleObjects仿真中,您会在条件变量上阻塞,并在唤醒时检查每个句柄。

之所以有条件变量列表(而不是单个条件变量),是因为您可能有两个线程在句柄上阻塞:线程1被阻塞在A和B上,线程2被阻塞在A和C上。发出B的信号不应唤醒线程2。由于每次调用WaitForMultipleObjects都会创建一个新的条件变量,在这种情况下,B和C将各自拥有一个不同的条件变量,而A则拥有两个条件变量。

如果您需要更详细的信息,您需要阅读文章本身。


3
Sun网站已删除链接URL。互联网档案馆有备份:https://web.archive.org/web/*/http://developers.sun.com/solaris/articles/waitfor_api.pdf - Philippe Chaintreuil
这里提出的解决方案允许等待所有或任何(根据函数参数选择)类型为solaris_win32_event_t的“事件”。这是一个(有点老式?)实现订阅模型的示例,但并没有提供答案。因此,在使用它之前,这个“解决方案”需要先解决问题 - 通过在单独的线程中等待每个信号量,并从那里发出“事件”信号。 - Zrin

0

使用多个独立的等待线程,例如:

  • 每个线程都在一个单独的信号量上等待。
  • 成功等待信号量后,任何给定的等待线程都会通过另一个信号量、条件变量或其他最方便的原语向想要“等待多个信号量”的线程发出信号。

看起来这个“解决方案”要求你在使用它之前先解决问题。因此,现在等待线程需要等待多个“最方便的原语”全部变为已发信号,而不是多个信号量。似乎并没有更容易。 - Ben Voigt
不,它等待一个原语,任何一个单独的等待线程都可以发出信号。例如,线程A等待sem A,线程B等待sem B,线程C等待sem C,但是在成功时,任何一个线程都可以发布到sem X,这是主等待线程正在等待的。当然,在实际情况下,您可能希望使其更加精美,以便主等待者知道哪些线程成功了。 - R.. GitHub STOP HELPING ICE
哦,我被vhallac提到的WaitForMultipleObjects搞混了,它可以等待全部。等待任何一个很容易,只需使用selectpoll即可。 - Ben Voigt
selectpoll本身不能等待信号量。您可以使用管道将所有辅助线程与select/poll一起作为共享同步对象,但是它们在这种情况下比信号量慢10到1000倍... - R.. GitHub STOP HELPING ICE

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