2

令我们大吃一惊的是,我们最近发现了这个。对于 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 之前的版本完全一样?

4

2 回答 2

1

不幸的是,你有问题。您所做的是根据实现细节而不是规范编写代码。

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

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

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

于 2009-07-20T12:02:38.480 回答
0

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

于 2009-07-20T12:03:27.027 回答