关键部分队列

时间:2013-04-04 07:59:35

标签: c++ winapi critical-section

Windows关键部分中是否没有队列概念?

我在专用线程中有以下渲染循环:

while (!viewer->finish)
{
  EnterCriticalSection(&viewer->lock);
  viewer->renderer->begin();
  viewer->root->render(viewer->renderer);
  viewer->renderer->end();
  LeaveCriticalSection(&viewer->lock);
}

主线程进行消息处理,当我处理鼠标事件时,我尝试进入相同的临界区,但由于某种原因,它运行渲染线程再进行一千次迭代(大约10秒)线程最终进入临界区。造成这种情况的原因 - 即使没有'队列'进入该部分,它不应该更像是50/50,而不是像我的情况那样99.9 / 0.1吗?两个线程都有0个优先级。

添加此类队列的好方法是什么?像bDoNotRenderAnything这样的简单旗帜是否足够?

编辑:我的案例中的解决方案只是添加一个事件对象(一个布尔变量可能也可以),每次消息处理程序需要访问临界区时设置它,并在使用后重置。如果设置了变量/事件,则渲染器不会进入该部分。这样消息处理程序就不必等待多次渲染迭代。

4 个答案:

答案 0 :(得分:4)

在旧版本的Windows中,保证按先到先得的原则获取关键部分。从Windows Server 2003 SP1开始不再是这种情况。

来自MSDN

  

从带有Service Pack 1(SP1)的Windows Server 2003开始,等待关键部分的线程不按先到先得的原则获取关键部分。此更改可提高性能大多数代码显着但是,某些应用程序依赖于先进先出(FIFO)排序,并且在当前版本的Windows上可能表现不佳或根本不表现(例如,已将关键部分用作速率限制器的应用程序)。为确保代码继续正常工作,您可能需要添加其他级别的同步。例如,假设您有一个生产者线程和一个使用临界区对象来同步其工作的消费者线程。创建两个事件对象,每个对象用于表示已准备好让另一个线程继续运行的每个线程。消费者线程将在进入临界区之前等待生产者发出其事件的信号,并且生产者线程将在进入临界区之前等待消费者线程发出其事件的信号。每个线程离开临界区后,它会发出事件信号以释放另一个线程。

     

Windows Server 2003和Windows XP:正在等待关键部分的线程被添加到等待队列中;它们被唤醒并且通常按照它们被添加到队列中的顺序获取关键部分。但是,如果以足够快的速率将线程添加到此队列,则由于唤醒每个等待线程所花费的时间,性能可能会降低。

答案 1 :(得分:3)

等待关键部分的线程不按先到先得的原则获得关键部分(MSDN

大多数情况下,您的工作线程拥有锁,因为它在释放锁后立即重新锁定。所以没有太多时间让其他线程在它空闲时唤醒并锁定锁。

答案 2 :(得分:1)

根据MSDN

There is no guarantee about the order in which waiting threads 
will acquire ownership of the critical section.

因此不确定线程​​将执行的顺序。如果你的相当短暂

viewer->renderer->begin();
viewer->root->render(viewer->renderer);
viewer->renderer->end();

序列设法重新获得CriticalSection,这可能会发生。

答案 3 :(得分:0)

您可以在渲染循环中使用SwitchToThread调用(在经过一定次数的迭代后)尝试快速修复,但我怀疑它是否足够好。