今天我在MSDN中遇到了这个问题:
“从Windows Server 2003开始 使用Service Pack 1(SP1),线程 等待关键部分不要 获得关于a的关键部分 先到先得,先到先得。这个 改变提高绩效 大多数代码显着然而, 一些应用依赖于先进, 先出(FIFO)排序和可能 表现不佳或根本不表现 当前版本的Windows(for 例如,已经有的应用程序 使用关键部分作为 速率限制)。确保你的 代码继续正常工作,你 可能需要添加额外的级别 同步。例如,假设 你有一个生产者线程和一个 正在使用的消费者线程 临界区对象同步 他们的工作。创建两个事件对象, 一个用于每个线程用于发信号 它准备好了另一个线程 继续。消费者线程将 等待制片人发出信号 在进入关键之前的事件 部分,以及生产者线程将 等待消费者线程发出信号 在进入批判之前的事件 部分。每个线程离开之后 关键部分,它标志着它的事件 释放另一个帖子。“
起初,我以为WTF?! - 我一直认为线程会按照他们试图获取它的顺序获得一个关键部分。虽然这对于Service Pack的行为来说似乎是一个奇怪的大变化,但是服务包是针对Windows的Server Edition而且我认为Vista正在开发中。
无论如何,所以它有点意义 - 这样调度程序旋转到的下一个等待线程将是接下来获得临界区的那个,至少我假设。这是唯一有意义的事情,除非他们决定随意选择乐趣;)。
尽管如此,这是我所做的一个假设,现在正在评估我的代码,以确保没有FIFO依赖的情况是一个问题。
有没有人对此有任何实际问题?虽然获取关键部分的线程的顺序并不保证是FIFO,但它通常不是FIFO吗?如果不是通常 FIFO(或接近FIFO),是否有人知道一个线程可以等待有争议的关键部分多长时间?如果它是一个低优先级的线程,这是否意味着如果总是有一个更高优先级的线程试图获得关键部分,它几乎可以无限期地等待(即使低优先级线程很久以前,如果遵守FIFO,那么下一个线程就是下一个线程)?是否有安全措施来防止这种情况,或者是否依赖于强制要求的辅助同步对象?
当然,这真的只对一个非常有争议的关键部分很重要。
我不知道,也许我做得太多了......但是有些事情困扰着我。任何见解都表示赞赏。谢谢;)
答案 0 :(得分:1)
这是我第一次听到这个,当我想到它时,它似乎不是一个问题。
如果我理解正确的话::
OldWay:
Thread A acquired the CritSec
Thread B waiting for the CritSec , tried to acquire it at time t
Thread C waiting for the CritSec , tried to acquire it at time t + dt
When Thread A releases the CritSec, OS ensures that Thread B acquires it.
NewWay:
Thread A acquired the CritSec
Thread B waiting for the CritSec , tried to acquire it at time t
Thread C waiting for the CritSec , tried to acquire it at time t + dt
When Thread A releases the CritSec, OS may choose any Thread to acquire it. So, it may be Thread B or C that will acquire it after A releases it.
我从未假设(并且不认为任何其他人假设)等待CritSec的线程将按照他们想要获取它的顺序获取它。
对于某些Profilers / Debuggers或某些性能监控机制来说,这可能会出现这个问题......
答案 1 :(得分:1)
根据我的经验,关键部分从不已成为FIFO(也许是文档团队在2003年将其称为“2003”新版本)。是的,它可能导致线程饥饿,我们已经看到了很多。如果您需要FIFO,则需要一个互斥锁。
互斥锁是内核对象,因此获取它们比环3乐观关键部分更昂贵。但是FIFO不是那些你可以(或者应该)必然会因为不必要而无法解除的事情之一,并且它不需要与"层次结构"线程(无论是什么 - 这是否意味着优先级?)。 1000个具有相同优先级的线程击中单个锁定很容易导致饥饿。