C++ C++;在具有同步队列的线程中等待通知

C++ C++;在具有同步队列的线程中等待通知,c++,multithreading,C++,Multithreading,我有一个这样的程序结构:一个线程接收任务并将其写入输入队列,多个线程处理任务并写入输出队列,一个线程用它的结果进行响应。当队列为空时,线程休眠数毫秒。队列中有互斥体,push执行lock(),popping执行try_lock(),并在队列中没有任何内容时返回 这是处理线程,例如: //working - atomic bool while (working) { if (!inputQue_->pop(msg)) { std::this_thread::sleep

我有一个这样的程序结构:一个线程接收任务并将其写入输入队列,多个线程处理任务并写入输出队列,一个线程用它的结果进行响应。当队列为空时,线程休眠数毫秒。队列中有互斥体,push执行lock(),popping执行try_lock(),并在队列中没有任何内容时返回

这是处理线程,例如:

//working - atomic bool
while (working) {
    if (!inputQue_->pop(msg)) {
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        continue;
    } else {
        string reply = messageHandler_->handle(msg);
        if (!reply.empty()) {
            outputQue_->push(reply);
        }
    }
}
我不喜欢的是,从收到任务到做出反应的时间,就像我用高分辨率时钟测量的那样,几乎是0,当没有睡眠的时候。当有睡眠时,它会变大。 我不希望cpu资源被浪费,我希望这样做:当接收线程获取任务时,它会通知其中一个正在处理的线程,该线程会等待,当处理任务完成时,它会以相同的方式通知响应线程。因此,我认为我将得到更少的时间花费和cpu资源将不会被浪费。我有一些问题:

  • 这会像我想象的那样起作用吗?唯一的区别是在通知时醒来
  • 为此,我必须创建两个条件变量:第一个用于接收线程和所有处理,第二个用于所有处理和响应?处理线程中的互斥必须是所有线程的公共互斥还是uniuqe
  • 我是否可以在if分支中创建唯一的\u锁(互斥锁)并等待\u for(),而不是在睡眠中等待
  • 如果某些处理线程正忙,notify_one()是否可以尝试唤醒其中一个线程,但不能唤醒空闲线程?我需要使用notify_all()
  • notify是否可能不会唤醒任何线程?如果是,是否有高概率

  • 一般来说,您对条件变量的考虑是正确的。我的建议更多地涉及此类功能的设计和可重用性。 其主要思想是实现ThreadPool模式,该模式具有具有工作线程数、方法submitTask、shutdown和join的构造函数。 有了这样的类,您将使用两个池实例:一个多线程用于处理,另一个(由您选择单线程)用于结果发送。 该池由任务阻塞队列和工作线程数组组成,每个线程执行相同的“pop Task and run”循环。阻塞队列封装mutex和cond_var。该任务是公共函子。 这也使您的设计采用了面向任务的方法,这在应用程序的未来有很多优势。 如果您喜欢此想法,欢迎您询问更多有关实施细节的问题。 致以最良好的祝愿,丹尼尔

    这会像我想象的那样起作用吗?唯一的区别是在通知时醒来

    是的,假设你做得正确

    为此,我必须创建两个条件变量:第一个用于接收线程和所有处理,第二个用于所有处理和响应?处理线程中的互斥必须是所有线程的公共互斥还是uniuqe

    您可以使用一个互斥锁和一个条件变量,但这会使它更复杂一些。我建议使用一个互斥锁,但线程可能需要等待的每个条件都有一个条件变量

    我是否可以在if分支中创建唯一的\u锁(互斥锁)并等待\u for(),而不是在睡眠中等待

    绝对不是。您需要在检查队列是否为空时保持互斥,并继续保持互斥直到调用
    wait\u for
    。否则,将破坏条件变量的整个逻辑。与条件变量关联的互斥体必须保护线程将要等待的条件,在这种情况下,队列是非空的

    如果某些处理线程正忙,notify_one()是否可以尝试唤醒其中一个线程,但不能唤醒空闲线程?我需要使用notify_all()

    我不知道你说的“免费线程”是什么意思。作为一般规则,如果无法在无法处理条件的条件变量上阻止线程,则可以使用
    notify_one
    。如果可能需要唤醒多个线程,或者可能会在条件变量上阻塞多个线程,并且可能会唤醒“错误线程”,则应使用
    notify_all
    ,也就是说,可能至少有一个线程无法执行任何需要执行的操作

    notify是否可能不会唤醒任何线程?如果是,是否有高概率


    当然,这是很有可能的。但这意味着在这种情况下没有线程被阻塞。在这种情况下,没有线程可以阻止该条件,因为线程必须在等待前检查该条件,并且在保持互斥锁的同时检查。提供这种原子“解锁并等待”语义是条件变量的全部目的。

    您拥有的机制称为轮询。线程反复检查(轮询)是否有可用数据。正如你提到的,它有浪费时间的缺点。(但这很简单)。你提到的你想要使用的是所谓的阻塞机制。这将取消线程调度,直到工作可用

    1) 是的(虽然我不知道你到底在想什么)

    2) a)是的,2个条件变量是一种方法。b) 公共互斥是最好的

    3) 您可能会将它们放在
    pop
    中,调用
    pop
    可能会造成阻塞

    4) 否。
    notify\u one
    只会将当前正在等待的线程从调用
    wait
    唤醒。此外,如果有多个用户正在等待,则不一定保证哪个用户将收到通知。(依赖于操作系统/库)

    5) 否。如果1+个线程正在等待,
    notify_one
    保证唤醒一个线程。但是如果没有线程在等待,则会使用通知(并且