首页 文章

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

提问于
浏览
0

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

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

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

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

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

2 回答

  • 2

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

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

    • 主线程产生多个线程(产生线程相对昂贵)

    • 主线程执行查询,而生成的线程启动,执行非常少,然后阻塞(启动/重启和阻塞相对昂贵)

    • 对于每一行,主线程唤醒每个线程(相对昂贵的重启和阻塞),除了其中一个线程之外的每个线程都会返回等待(非常浪费)

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

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

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

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

  • 0

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

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

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

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

    你也可以使用pthread_barrier_wait() .

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

    • pthread_barrier_init()初始化障碍(计数= 1# Worker )
      在每个worker中

    • ,在循环中调用pthread_barrier_wait();当返回时,新数据准备就绪

    • 在主线程中,调用pthread_barrier_wait()来发出信号工作人员

    不幸的是(正如OP注释),在下一次迭代中,在先前激活的 Worker 完成其工作之前,不会唤醒任何 Worker .

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

相关问题