C++ C++;在具有同步队列的线程中等待通知
我有一个这样的程序结构:一个线程接收任务并将其写入输入队列,多个线程处理任务并写入输出队列,一个线程用它的结果进行响应。当队列为空时,线程休眠数毫秒。队列中有互斥体,push执行lock(),popping执行try_lock(),并在队列中没有任何内容时返回 这是处理线程,例如:C++ C++;在具有同步队列的线程中等待通知,c++,multithreading,C++,Multithreading,我有一个这样的程序结构:一个线程接收任务并将其写入输入队列,多个线程处理任务并写入输出队列,一个线程用它的结果进行响应。当队列为空时,线程休眠数毫秒。队列中有互斥体,push执行lock(),popping执行try_lock(),并在队列中没有任何内容时返回 这是处理线程,例如: //working - atomic bool while (working) { if (!inputQue_->pop(msg)) { std::this_thread::sleep
//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资源将不会被浪费。我有一些问题:
一般来说,您对条件变量的考虑是正确的。我的建议更多地涉及此类功能的设计和可重用性。 其主要思想是实现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
保证唤醒一个线程。但是如果没有线程在等待,则会使用通知(并且