Windows 2003 SP1 中的关键部分行为更改

Posted

技术标签:

【中文标题】Windows 2003 SP1 中的关键部分行为更改【英文标题】:Critical Section change in behavior in Windows 2003 SP1 【发布时间】:2011-04-27 09:51:57 【问题描述】:

今天我在MSDN看到了这个:

"从 Windows Server 2003 开始 使用 Service Pack 1 (SP1),线程 等待关键部分不要 获取关键部分 先到先得。这 改变提高绩效 对于大多数代码来说意义重大。然而, 一些应用程序依赖于先进技术, 先进先出 (FIFO) 排序,并且可能 表现不佳或根本没有 当前版本的 Windows(对于 例如,已被 使用临界区作为 速率限制器)。以确保您的 代码继续正常工作,你 可能需要添加一个额外的级别 同步。例如,假设 你有一个生产者线程和一个 正在使用的消费者线程 要同步的临界区对象 他们的工作。创建两个事件对象, 每个线程使用一个来发出信号 它已准备好用于另一个线程 继续。消费者线程将 等待生产者发出信号 进入关键之前的事件 部分,生产者线程将 等待消费者线程发出信号 在进入关键之前它的事件 部分。每个线程离开后 临界区,它标志着它的事件 释放另一个线程。”

一开始我还以为是WTF?! - 我一直认为线程会按照它们尝试获取临界区的顺序来获取它。尽管这对于 Service Pack 而言似乎是一个非常大的行为变化,但该 Service Pack 是针对 Windows Server Edition 的,我相信当时 Vista 正在开发中。

无论如何,这有点道理——这样调度程序旋转到的下一个等待线程将是下一个获得关键部分的线程,至少我假设。因此,这是唯一有意义的事情,除非他们决定为了好玩而随机选择;)。

不过,这是我所做的假设,现在我正在评估我的代码,以确保不存在依赖 FIFO 的情况。

有没有人对此有任何实际问题?虽然线程获取临界区的顺序不保证是先进先出,但通常不是先进先出吗?如果不是通常 FIFO(或接近FIFO),有谁知道线程可以等待激烈竞争的关键部分多长时间?如果它是一个低优先级线程,这是否意味着如果总是有一个更高优先级的线程试图获取临界区,它可以几乎无限期地等待(即使如果遵循 FIFO,低优先级线程很久以前就是下一个线程)?是否有安全措施来防止这种情况,或者是否强制要求依赖辅助同步对象?

当然,这只对竞争激烈的关键部分很重要。

我不知道,也许我做的太多了……但是这件事让我很困扰。任何见解都值得赞赏。谢谢;)

【问题讨论】:

【参考方案1】:

根据我的经验,关键部分从来没有是 FIFO(也许文档团队会说这是 2003 年的新功能)。是的,它会导致线程饥饿,我们已经看到了很多。如果需要 FIFO,则需要互斥体。

互斥体是内核对象,因此获取它们比环 3 乐观临界区更昂贵。但是 FIFO 不是您可以(或应该)因为没有必要而立即解雇的那些事情之一,并且它不必与线程的“层次结构”有任何关系(不管是什么——这是否意味着优先级?) . 1000个同等优先级的线程碰到一个锁很容易导致饿死。

【讨论】:

感谢您的洞察力。我无法评论关键部分是 FIFO,但我一直认为它们是,如果他不确定(嗯..谁知道),那位文档作者肯定不会写一整段关于这个“变化”的文章。我绝对关心这个问题,这就是我写这篇文章的原因;)。我知道事情很容易出错。【参考方案2】:

这是我第一次听到这个,当我想到它时,这似乎不是问题。

如果我理解正确的话::

老路:

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.

新路:

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 的线程会按照他们想要获取它的顺序获取它。

这可能是某些分析器/调试器或某些性能监控机制做出此假设的问题...

【讨论】:

你真的无法想象这是许多人的假设吗?老实说,我可以。也就是说,该假设的影响值得怀疑,并且仅适用于高负载。 转念一想,我几乎总是使用相同类型的工作线程来平衡多个 CPU 内核上的工作负载。如果有人有一个分层线程(不是相同类型或相同角色)池,那么可能需要/期望这种 FIFO 行为...... 无论如何,这似乎是一个静音点,你是对的。很少有依赖于关键部分的顺序,这只是在某些情况下需要注意的事情,特别是如果你有某种级联的关键部分排列我猜(虽然我肯定没有)。在这种奇怪而罕见的情况下,FIFO假设的失败可能会导致死锁..好吧,至少如果我直截了当的话;) 明确地说,我们说的是临界区,而不是互斥体。当然,临界区在理论上是互斥体的一种形式,在任何情况下都是同步对象,但在 Windows 实现中它们是截然不同的。因此,应该将上面的示例编辑为“关键部分”而不是“互斥体”......恕我直言。 我通常以 windows 和 unix 为目标,所以我对 CritSec 和 pthread_mutex 都使用了“mutex”这个词...

以上是关于Windows 2003 SP1 中的关键部分行为更改的主要内容,如果未能解决你的问题,请参考以下文章

windows 2003 sp1 P2V成功之后虚拟机登录后自动关机

安装 microsoft platform SDK for Windows Server 2003 SP1 后在 VS 2005 中编译时出现问题

在某些特殊情况下,Win32 ShowWindow api 在 Windows 7 SP1 上的行为是不是不同?

windows server 2008 R2 SP1 安装exchange 2010

Windows 32位简体中文版和Windows2003 sp2 32位镜像iso下载地址

VS 2003:服务包安装确认