0

我的程序根据行的字段之一在不同的线程中处理数据库行。主线程产生“工人”,执行查询,然后,对于每一行,需要唤醒所有工人,以便其中一个消耗该行。

现在,使用 pthread_cond_broadcast() 似乎是最合乎逻辑的选择。但是,在这种情况下,工作人员都必须使用相同的 mutex在 pthread_cond_wait() 内等待。

在我的情况下,这是次优的,因为这意味着,工人将一次被唤醒(我不需要) - 而不是一次全部唤醒。是的,我确实希望他们醒来——他们都会从新的 DB 行中读取一个字段,之后除了一个之外的所有字段都将返回等待下一行。我不需要同步它们。

我想,我会在每个线程中使用带有 pthread_cond_wait() 的虚拟线程特定互斥锁,但这不起作用(只有一个线程被唤醒)。标准说,使用不同的互斥锁等待相同的条件变量(就像我一样)是未定义的。

那么,有没有办法一次通知所有线程?谢谢!

4

2 回答 2

2

我认为你需要更多地描述这个问题以及为什么你(试图)开始这样做。如果最好的方法是做一些完全不同的事情,不涉及在没有互斥锁的情况下一次唤醒所有线程,我不会感到惊讶。

对我来说,你的描述听起来像:

  • 主线程产生几个线程(产生一个线程相对昂贵)
  • 主线程进行查询,而生成的线程启动,做的很少,然后阻塞(启动/重新启动和阻塞相对昂贵)
  • 对于每一行,主线程唤醒每个线程(相对昂贵的重新启动和阻塞),并且除其中一个之外的每个线程都返回等待(非常浪费)

在不知道您为什么要这样做的情况下,我假设根本不使用任何线程会更快(例如,主线程能够比主线程检查该行并告诉一个人更快地处理一行产生线程来处理它并无缘无故地打扰其他线程)。

如果处理一行需要很长时间,那么我会考虑让工作线程在 FIFO 队列上等待,这样主线程将“处理这一行”命令推送到队列中,而第一个线程从队列进程中获取它那一排。

当然我不知道你为什么要做你想做的事,因此任何建议都只是猜测。

TL; DR:我认为你的问题有点像想减肥的人问“砍掉自己腿的最好方法是什么”(最实际的答案与实际提出的问题无关)。

于 2012-12-30T07:25:25.783 回答
0

对于条件变量,假设有一些相关的“条件”(在您的情况下是数据行)需要专门检查和更新(因此是互斥锁)。无论您选择哪种其他机制,您都需要弄清楚如何确保对“工作队列”的独占访问(无论是单个插槽还是真正的队列)。

使用共享队列,数据结构将始终有 2 个写入者(主线程 + 预期工作线程)和 N-1 个读取者。您可以使用读写锁 (rwlock) 来确保完整性。

或者,您可以有 N 个单独的队列(每个工作人员一个)。您会将数据行的副本推送给每个工作人员。

至于一次唤醒多个线程:您可以让您的工作人员“休眠”(例如使用 select())并使用 pthread_signal()(在循环中)唤醒它们。

您也可以使用pthread_barrier_wait()

pthread_barrier_wait() 函数应在屏障引用的屏障处同步参与线程。调用线程应阻塞,直到所需数量的线程调用了指定屏障的 pthread_barrier_wait()。

当所需数量的线程调用了指定屏障的 pthread_barrier_wait() 时,常量 PTHREAD_BARRIER_SERIAL_THREAD 应返回给一个未指定的线程,并且零应返回给每个剩余线程。此时,屏障应重置为最近引用它的 pthread_barrier_init() 函数的结果。

  1. 使用pthread_barrier_init()初始化屏障(count = 1 + # of workers)
  2. 在每个worker中,循环调用pthread_barrier_wait();当它返回时,新数据已准备好
  3. 在主线程中,调用 pthread_barrier_wait() 向工作人员发出信号

不幸的是(正如 OP 所指出的),在下一次迭代中,在先前激活的工作人员完成其工作之前,不会唤醒任何工作人员。

一个更简单的架构将使主线程将事件分派给适当的工作人员(而不是唤醒所有工作人员并让他们弄清楚哪个是预期的接收者)。除非您拥有与 worker 一样多的核心,否则测试无论如何都不会真正并行发生。此外,即使您有足够的核心让工作人员并行运行,其中 N-1 也不会在完成测试之前得知“获胜者”已接手工作,因此所有核心的总工作量更高.

于 2012-12-30T06:23:44.297 回答