具有多个生产者的高效消费者线程 [英] Efficient consumer thread with multiple producers
问题描述
我试图通过在必要时跳过昂贵的事件操作来使生产者/消费者线程状况更有效,例如:
I am trying to make a producer/consumer thread situation more efficient by skipping expensive event operations if necessary with something like:
//cas(variable, compare, set) is atomic compare and swap
//queue is already lock free
running = false
// dd item to queue – producer thread(s)
if(cas(running, false, true))
{
// We effectively obtained a lock on signalling the event
add_to_queue()
signal_event()
}
else
{
// Most of the time if things are busy we should not be signalling the event
add_to_queue()
if(cas(running, false, true))
signal_event()
}
...
// Process queue, single consumer thread
reset_event()
while(1)
{
wait_for_auto_reset_event() // Preferably IOCP
for(int i = 0; i < SpinCount; ++i)
process_queue()
cas(running, true, false)
if(queue_not_empty())
if(cas(running, false, true))
signal_event()
}
显然,要使这些事情正确无误,所以上面的伪代码正确吗?可以用一种解决方案向事件发出比实际需要更多的信号,但没有一种解决方案可以针对每个项目发出信号.
Obviously trying to get these things correct is a little tricky(!) so is the above pseudo code correct? A solution that signals the event more than is exactly needed is ok but not one that does so for every item.
推荐答案
这属于停止混乱并重新开始工作"子类别,称为过早优化". :-)
This falls into the sub-category of "stop messing about and go back to work" known as "premature optimisation". :-)
如果昂贵的"事件操作占用了大量时间,则您的设计是错误的,而不是使用生产者/消费者,您应该使用关键部分/互斥体,并从调用线程中进行工作.
If the "expensive" event operations are taking up a significant portion of time, your design is wrong, and rather than use a producer/consumer you should use a critical section/mutex and just do the work from the calling thread.
如果您真的很担心,我建议您对应用程序进行概要分析.
I suggest you profile your application if you are really concerned.
已更新:
正确答案:
制作人
ProducerAddToQueue(pQueue,pItem){
EnterCriticalSection(pQueue->pCritSec)
if(IsQueueEmpty(pQueue)){
SignalEvent(pQueue->hEvent)
}
AddToQueue(pQueue, pItem)
LeaveCriticalSection(pQueue->pCritSec)
}
消费者
nCheckQuitInterval = 100; // Every 100 ms consumer checks if it should quit.
ConsumerRun(pQueue)
{
while(!ShouldQuit())
{
Item* pCurrentItem = NULL;
EnterCriticalSection(pQueue-pCritSec);
if(IsQueueEmpty(pQueue))
{
ResetEvent(pQueue->hEvent)
}
else
{
pCurrentItem = RemoveFromQueue(pQueue);
}
LeaveCriticalSection(pQueue->pCritSec);
if(pCurrentItem){
ProcessItem(pCurrentItem);
pCurrentItem = NULL;
}
else
{
// Wait for items to be added.
WaitForSingleObject(pQueue->hEvent, nCheckQuitInterval);
}
}
}
注意:
- 该事件是手动重置事件.
- 关键部分保护的操作非常快捷.仅当队列转换为空状态或从空状态转换时,才设置或重置事件.必须在关键区域内设置/重置它,以避免出现竞争情况.
- 这意味着关键部分仅保留了很短的时间.这样竞争就很少了.
- 除非有争议,否则关键部分不会阻止.因此,上下文切换将很少见.
假设:
- 这是一个真正的问题,而不是家庭作业.
- 生产者和消费者将大部分时间都花在做其他事情上,即将物品准备好放入队列,在将它们从队列中删除后进行处理.
- 如果他们大部分时间都在执行实际的队列操作,则不应使用队列.我希望这很明显.
这篇关于具有多个生产者的高效消费者线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!