2

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

4 回答 4

4

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

MSDN

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

Windows Server 2003 和 Windows XP: 在临界区等待的线程被添加到等待队列;它们被唤醒并通常按照它们添加到队列中的顺序获取关键部分。但是,如果线程以足够快的速度添加到此队列中,则性能可能会因为唤醒每个等待线程所需的时间而降低。

于 2013-04-04T08:03:10.487 回答
3

在临界区等待的线程不会以先到先服务的方式获取临界区 ( MSDN )

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

于 2013-04-04T08:07:59.850 回答
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,这可能会发生。

于 2013-04-04T08:07:02.983 回答
0

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

于 2013-04-04T08:25:26.467 回答