临界区队列

Critical section queue

本文关键字:队列 临界区      更新时间:2023-10-16

在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。

添加这样的队列的好方法是什么?像bdonotrender这样简单的标志是否足够?

编辑:在我的情况下,解决方案是简单地添加一个事件对象(一个布尔变量可能也会工作),每次消息处理程序需要访问临界区时设置,并在使用它后重置。如果设置了变量/事件,渲染器就不会进入section。这样,消息处理程序就不必等待多个呈现迭代。

在旧版本的Windows中,关键区是按照先到先得的原则获得的。从Windows Server 2003 SP1开始,这种情况将不再出现。

来自MSDN:

从Windows Server 2003 with Service Pack 1 (SP1)开始,等待临界区的线程不会以先到先服务的方式获取临界区。这个变化显著提高了大多数代码的性能。然而,一些应用程序依赖于先进先出(FIFO)排序,在当前版本的Windows上可能表现不佳或根本无法运行(例如,使用临界区作为速率限制器的应用程序)。为了确保代码继续正常工作,您可能需要添加额外的同步级别。例如,假设您有一个生产者线程和一个消费者线程,它们正在使用临界区对象来同步它们的工作。创建两个事件对象,每个线程一个,用来表示它已准备好让另一个线程继续执行。消费者线程将在进入临界区之前等待生产者发出事件信号,生产者线程将在进入临界区之前等待消费者线程发出事件信号。当每个线程离开临界区后,它会向自己的事件发出信号,释放另一个线程。

Windows Server 2003和Windows XP:等待临界区的线程被添加到等待队列;它们被唤醒,通常按照它们加入队列的顺序获得临界区。但是,如果以足够快的速度将线程添加到此队列,则由于唤醒每个等待线程所需的时间,性能可能会降低。

等待临界区的线程不按照先到先服务的原则(MSDN)获取临界区

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

根据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 over,这可能会发生

您可以通过在渲染循环中使用SwitchToThread调用(在一定次数的迭代之后)来尝试快速修复,尽管我怀疑它将是足够好的解决方案