C++ 多线程访问队列的推荐模式…工作线程应该做什么?
我有一个由线程a添加到的对象队列。线程B正在从队列中删除对象并对其进行处理。可能有多个线程A和多个线程B 当队列被“推”到时,以及当“前端”被“推”到并从中“弹出”时,我使用互斥锁,如下面的伪代码所示: 线程A调用此项以添加到队列:C++ 多线程访问队列的推荐模式…工作线程应该做什么?,c++,multithreading,queue,C++,Multithreading,Queue,我有一个由线程a添加到的对象队列。线程B正在从队列中删除对象并对其进行处理。可能有多个线程A和多个线程B 当队列被“推”到时,以及当“前端”被“推”到并从中“弹出”时,我使用互斥锁,如下面的伪代码所示: 线程A调用此项以添加到队列: void Add(object) { mutex->lock(); queue.push(object); mutex->unlock(); } 线程B按如下方式处理队列: object GetNextTargetToWorkO
void Add(object)
{
mutex->lock();
queue.push(object);
mutex->unlock();
}
线程B按如下方式处理队列:
object GetNextTargetToWorkOn()
{
object = NULL;
mutex->lock();
if (! queue.empty())
{
object = queue.front();
queue.pop();
}
mutex->unlock();
return(object);
}
void DoTheWork(int param)
{
while(true)
{
object structure;
while( (object = GetNextTargetToWorkOn()) == NULL)
boost::thread::sleep(100ms); // sleep a very short time
// do something with the object
}
}
让我烦恼的是,如果没有对象,就去睡觉。虽然存在要处理的对象,但这很好。但是当线程正在等待工作时,有两个问题
a) while循环正在消耗资源b) 睡眠意味着浪费的时间是一个新的对象进入处理
有更好的模式来实现同样的功能吗?如果使用旋转等待,更好的设计是使用监视器。请阅读有关的详细信息。 可以找到一个使用std::condition_变量的跨平台解决方案,并提供了一个很好的示例 a) while循环正在消耗资源 b) 睡眠意味着浪费的时间是一个新的对象进入处理 根据我的经验,您使用的睡眠实际上“修复”了这两个问题 a) 资源消耗量很小,占用的可用cpu周期非常少 b) 睡眠是而不是在我开发的操作系统上浪费的时间 c) 睡眠可以影响“反应时间”(又称延迟),但很少成为问题(除了中断) 睡眠时间可能比在这个简单循环中花费的时间长几个数量级。i、 e.这并不重要
IMHO-这是“好邻居”策略的一个正常实现,即尽快放弃处理器
在我的桌面AMD64双核Ubuntu15.04上,一个信号量强制的上下文切换大约需要13分钟 100毫秒==>100000美元。。这是4个数量级的差异,即非常小 在我使用过的5个操作系统(Linux、vxWorks、OSE和其他几个嵌入式系统操作系统)中,睡眠(或其等效物)是放弃处理器的正确方式,这样当一个线程处于睡眠状态时,它就不会被阻止运行另一个线程
注意:某些操作系统的睡眠可能不会放弃处理器。所以,你应该始终确认。我没找到。哦,但我承认我没有在Windows上做过很多工作。要使用的“模式”是一个条件变量。。。或信号量……旁注:不要显式调用
lock
和unlock
。C++11为您提供了异常/程序员安全的RAII管理互斥锁
请使用它。在Windows上,(在我的i7上)通过将一个单元发送到线程正在等待的信号量(假设有一个内核可用),使线程运行需要5-8个U。Windows Sleep()API执行您预期的操作—从调用线程中删除执行,直到睡眠间隔结束,此时线程再次准备就绪(然后在内核可用时运行)。IIRC虽然如此,发送到等待线程的信号量为等待线程提供了临时优先级提升,但Sleep()expiry没有。是的,监视器模式对我来说非常有效-谢谢