【问题标题】:Starvation of threads with Windows 2003 SP2Windows 2003 SP2 的线程饥饿
【发布时间】:2009-07-23 16:46:45
【问题描述】:

令我们惊讶的是,我们最近发现了this。对于 Windows 2003 的 SP1,Microsoft 改变了临界区的行为方式。想要访问它们的早期线程以 FIFO 方式提供服务。现在它们以纯粹的“随机”方式提供。

在我们的例子中,我们有这样的事情:

// I now it's kind of ugly design but works
void Class:RunInThread()
{
   while(m_Running)
   {
       EnterCriticalSection(&m_CS);
       DoSomeStuffWithList();
       LeaveCriticalSection(&m_CS);
   }
} 
void Class::AddToList()
{
       EnterCriticalSection(&m_CS);
       AddSomeStuffToList();
       LeaveCriticalSection(&m_CS);
}

因此,随着 2003 SP2 中新实现的临界区,AddToList 可能会死于饥饿,因为无法保证它会被唤醒。

这个例子有点极端,但另一方面,我有 数百万行的代码是在假设对关键部分的访问是序列化的情况下编写的。

有没有办法关闭这个新的临界区?

编辑:由于无法返回旧版本,我正在考虑只进行全局搜索和替换以将 {Enter,Leaver}CriticalSection 更改为 My{Enter,Leave}CriticalSection。您是否知道应该如何实现它以使其行为完全像 SP2 之前的版本?

【问题讨论】:

    标签: windows-vista windows-server-2008 windows-server-2003 critical-section


    【解决方案1】:

    很遗憾,您遇到了问题。您所做的是根据实现细节而不是规范编写代码。

    EnterCriticalSection 一直被记录为不保证线程将获取该部分的任何特定顺序,但事实上,在旧版本的操作系统中,它们以 FIFO 方式这样做,这就是您的代码的基础周围。

    关闭这种新行为方式的方法是不安装 SP1。

    现在,话虽如此,我不相信您的代码会有不利的问题,除非您的线程优先级完全不同。当然,这两种方法中的一种可能会连续多次获取该部分,即使另一种方法也在等待,但这应该不是问题。

    【讨论】:

    • 可能存在实际问题。特别是我在一些遗留项目中遇到了它们,其中所有非线程安全代码都被锁定在一个巨大的关键部分中。你可以说它本来就不应该是一个关键部分,但它仍然可以在 XP 上运行并在 2003 年崩溃。而且它是真正的代码。
    • 但同样,它依赖于实现细节而不是规范。正如您在答案中发布的那样,如果可能的话,最好在很短的时间内保持锁定。当然,写得不好的代码会有这样的变化问题,这是毫无疑问的。从您发布的链接中的文章来看,线程处理、锁和调度不适合外行,您需要非常确定自己做的正确。 “碰巧起作用”现在可能已经足够好,但不是面向未来的。
    【解决方案2】:

    这是一个已知问题:http://www.bluebytesoftware.com/blog/PermaLink,guid,e40c2675-43a3-410f-8f85-616ef7b031aa.aspx 不幸的是,唯一的方法似乎是构建代码,使其在关键部分花费更少的时间。

    【讨论】:

      猜你喜欢
      • 2012-07-26
      • 1970-01-01
      • 2016-06-23
      • 1970-01-01
      • 2017-12-15
      • 2021-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多