在没有互斥锁的情况下立即唤醒所有线程

时间:2012-12-30 05:46:20

标签: c pthreads

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

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

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

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

那么,有没有办法立即通知所有线程 ?谢谢!

2 个答案:

答案 0 :(得分:2)

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

对我而言,您的描述听起来像是:

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

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

如果处理一行需要很长时间,那么我会考虑让工作线程等待FIFO队列,这样主线程就会将“处理此行”命令推送到队列中,并将第一个线程从队列中抓取队列处理该行。

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

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

答案 1 :(得分:0)

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

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

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

一次唤醒多个线程:你可以让你的工作人员“睡觉”(例如用select())并用pthread_signal()唤醒它们(在一个循环中)。

您也可以使用pthread_barrier_wait()

  

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

     

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

  1. 使用pthread_barrier_init()(计数= 1 +#工人数)
  2. 初始化障碍
  3. 在每个worker中,在循环中调用pthread_barrier_wait();当它返回时,新数据准备就绪
  4. 在主线程中,调用pthread_barrier_wait()来表示工作人员
  5. 不幸的是(正如OP注释),在下一次迭代中,在先前激活的工作人员完成其工作之前,不会唤醒任何工作人员。

    更简单的架构会将主线程调度事件发送给适当的工作人员(而不是唤醒所有工作人员并让他们弄清楚哪一个是预期的接收者)。除非你拥有与工作人员一样多的内核,否则测试并不会真正并行发生。此外,即使您有足够的内核让工作人员并行运行,N-1也不会知道“胜利者”在完成测试之前已经完成了工作,因此所有核心的工作总量更高