如果一个线程试图获取一个锁,并且它被占用了,那么它应该进入睡眠状态,并保持睡眠状态,直到锁被释放。如果一个线程释放了一个锁(它被创建它的线程占用),它应该唤醒线程。
我的问题是,如果我们在锁地址上唤醒所有线程,还是在锁地址上唤醒单个线程(在锁释放之后),这会有区别吗?如果我们要唤醒一个线程,那么唤醒哪个线程是有意义的,第一个在锁地址上进入睡眠状态?
我可以看到唤醒一个线程的一些好处,因为如果我们唤醒所有线程,n-1可能会回到睡眠状态。但我不知道唤醒单个线程是否有缺点。
发布于 2013-01-23 13:09:34
我相信您混淆了windows锁(互斥、临界区)和锁监视器(在C#中,.Net监视器可以使用关键字C#作为进入/退出块的语法糖)。
Windows互斥锁和临界区只能进入和退出,即只有一个队列与它们关联。队列中的所有线程都在等待锁被释放,当这种情况发生时,队列中的下一个线程将控制锁并开始运行。所有这些都是自动发生的。当前持有锁的线程不参与此操作,它不能选择唤醒等待释放锁的一个或多个其他线程。
.NET的Monitor有两个队列:一个就绪队列和一个等待队列。
就绪队列的行为与Win32互斥锁或临界区队列完全相同,并使用Enter/Leave方法进行控制。
等待队列是使用Wait/Pulse/PulseAll方法控制的单独队列。这些方法只能由持有监视器的线程调用。当线程调用Wait时,它会释放Monitor并进入等待队列。然后,不同的线程可以调用Pulse来移动一个线程,或者调用Pulse All来将所有线程从等待队列移动到就绪队列(记住调用Pulse/PulseAll的线程持有监视器)。
从计算机科学的角度来看,监视器是同步线程所需的单一原语(信号量、事件、互斥锁、屏障等都可以用监视器来实现),从实用的角度来看,监视器作为互斥锁非常有用,并且适用于需要由两个线程在锁步中执行操作的情况。但是,在大多数情况下,使用事件时代码的可读性更好。
进一步阅读:
Wikipedia page about Monitors for the historic/computer science aspect
MSDN Monitor class
https://stackoverflow.com/questions/14469440
复制相似问题