0

如果一个线程试图获取一个锁并被占用,它应该进入睡眠状态并保持睡眠状态直到锁被释放。如果一个线程释放了一个锁(它被创建它的线程占用),它应该唤醒线程。

我的问题是,如果我们唤醒锁定地址上的所有线程与锁定地址上的单个线程(锁定释放后),这有什么不同吗?如果我们要唤醒一个线程,那么唤醒哪个线程有意义,第一个在锁定地址上进入睡眠状态?

我可以看到唤醒一个线程的一些优势,如果我们唤醒所有线程,n-1 可能会重新进入睡眠状态。但是我不知道唤醒单个线程是否有缺点。

4

1 回答 1

2

我相信您将 Windows 锁(互斥锁,关键部分)与 .Net 监视器(在 C# 中可以使用关键字 lock 作为进入/退出块的语法糖)混淆。

Windows 互斥锁和临界区只能进入和退出,即只有一个与它们关联的队列。队列中的所有线程都等待锁被释放,当这种情况发生时,队列中的下一个线程将控制锁并开始运行。这一切都是自动发生的。当前持有锁的线程与此无关,它不能选择唤醒一个或多个等待释放锁的其他线程。

.Net 的 Monitor 有两个队列:就绪队列和等待队列。

就绪队列的行为与 Win32 Mutex 或临界区队列完全相同,并使用 Enter/Leave 方法进行控制。

等待队列是使用 Wait/Pulse/PulseAll 方法控制的单独队列。这些方法只能由持有 Monitor 的线程调用。当线程调用 Wait 时,它会释放 Monitor 并进入等待队列。然后另一个线程可以调用 Pulse 来移动一个线程,或者调用 Pulse All 来将所有线程从等待队列移动到就绪队列(记住调用 Pulse/PulseAll 的线程持有 Monitor。)

从计算机科学的角度来看,监视器是同步线程所需的单个原语(信号量、事件、互斥体、屏障等都可以用监视器来实现),从实际的角度来看,监视器可用作互斥体,并且适用于以下情况动作需要由两个线程以锁步执行。然而,大多数时候代码在使用事件时更具可读性。

进一步阅读:

关于历史/计算机科学方面的监视器的维基百科页面

MSDN 监视器类

于 2013-01-23T05:09:33.677 回答