实现锁定和阻塞线程

时间:2013-01-22 22:43:51

标签: synchronization operating-system thread-safety locking block

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

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

我可以看到唤醒一个线程的一些优势,因为如果我们全部醒来,n-1可能会重新入睡。但我不知道唤醒单个线程是否有缺点。

1 个答案:

答案 0 :(得分:2)

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

只能输入和退出Windows互斥锁和关键部分,即只有一个与之关联的队列。队列中的所有线程都等待释放锁定,当发生这种情况时,队列中的下一个线程将控制锁定并开始运行。所有这些都会自动发生当前持有锁的线程没有任何部分,它不能选择唤醒一个或多个等待锁被释放的其他线程。

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

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

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

从计算机科学的角度来看,Monitor是需要同步线程的单一原语(信号量,事件,互斥体,障碍等都可以用监视器实现),从实用的角度来看,监视器可用作互斥体和对于需要由锁定步骤中的两个线程执行操作的情况。但是大多数情况下,代码在使用事件时更具可读性。

进一步阅读:

Wikipedia page about Monitors for the historic/computer science aspect

MSDN Monitor class