3

今天我在MSDN中遇到了这个:

每个线程使用一个来表示它已准备好让另一个线程继续进行。消费者线程在进入临界区之前将等待生产者发出其事件信号,而生产者线程将在进入临界区之前等待消费者线程发出其事件信号。在每个线程离开临界区后,它会发出信号来释放另一个线程。”

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

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

尽管如此,这是我所做的假设,现在正在评估我的代码以确保没有任何依赖 FIFO 的情况是问题。

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

当然,这真的只在竞争激烈的关键部分才重要。

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

4

2 回答 2

1

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

如果我理解正确::

老路:

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

也许这对于某些分析器/调试器或某些性能监控机制来说是一个问题,这些机制做出了这个假设......

于 2011-12-02T07:25:10.283 回答
1

以我的经验,关键部分从来都不是先进先出(也许 doc 团队会说这是 2003 年的新功能)。是的,它会导致线程饥饿,我们已经看到了很多。如果需要 FIFO,则需要互斥体。

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

于 2017-04-07T01:02:01.070 回答