临界区队列
Critical section queue
在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调用(在一定次数的迭代之后)来尝试快速修复,尽管我怀疑它将是足够好的解决方案
- 在同步问题中,弱指针可以代替互斥锁或临界区吗?
- 多线程环境下,其他线程永远无法访问临界区
- 如果一个线程在临界区上调用Acquire(),如果另一个线程调用Release(),该锁会被释放吗?
- 是否需要临界区?
- 当我的堆栈加倍时,它会给我临界区错误!_ctrlvalidHeappointer
- 确定Windows线程是否处于临界区或类似的位置
- 这段代码是一个工作的临界区包装器类吗?
- 临界区通过constexpr
- 临界区队列
- 出乎意料的性能提升与OpenMP临界区
- 如何使用Boost创建临界区?
- 临界区最简单的实现
- 由两个线程访问的共享队列的临界区代码是什么?
- c++ 11有临界区吗?
- 如何避免临界区和SendMessage之间的死锁
- Windows临界区公平性
- 线程同步-临界区或互斥锁
- 是否寄存器读/写需要临界区保护
- 如何在两个类之间共享单个临界区
- 什么是临界区