信号量 vs. 监视器 - 有什么区别?

274

一个监视器和一个信号量的主要区别是什么?


10
你可以将“monitor”看作是一个二元信号量。 - Maxim Egorushkin
2
请阅读这篇文章:http://www.albahari.com/threading/part2.aspx。我阅读了这篇文章,是我读过最好的关于线程的文章。 - Shantanu Gupta
7
我不认为你是正确的,Maxim。如果我没记错的话,信号量是一种“低级”结构,而监视器则是一个完整的对象。我记得在大学的操作系统课程中我们简要讲解了监视器,但我不记得监视器与互斥锁有何不同,除了它是面向对象的。我记得有一个问题可以用监视器来解决,但由于C语言的限制,我们不能在课堂上使用这个方法。 - user919860
2
Semaphore和Monitor在功能上有很大的差异,但是它们的作用是等效的,因为你可以从一个实现另一个。你可以阅读Hoare的原始论文,该论文证明了它们的等效性。论文链接:http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CC4QFjAA&url=http%3A%2F%2Fjohn.cs.olemiss.edu%2F~dwilkins%2FSeminar%2FS05%2FMonitors.pdf&ei=C1KFT4ypAozqrQe-kqWxBg&usg=AFQjCNHsqKHJRPfPyD7DiRxovfuud2jshw&sig2=xRt4RdUf4cSVOCR9A5AEzg - Thanh DK
1
@MaximEgorushkin 你的意思是互斥锁是一种二元信号量。 - philipxy
显示剩余2条评论
7个回答

600

监视器是一种旨在被多个线程访问的对象。监视器对象的成员函数或方法将实施互斥,因此在任何给定时间只有一个线程可以对对象执行任何操作。如果一个线程正在执行对象的成员函数,则任何试图调用该对象的成员函数的其他线程都必须等待直到第一个线程完成。

信号量是一种较低级别的对象。您可以使用信号量来实现监视器。信号量本质上只是一个计数器。当计数器为正时,如果线程尝试获取信号量,则允许它,并且计数器减1。当线程完成后,它释放信号量并增加计数器。

如果当一个线程尝试获取信号量时,计数器已经为零,则它必须等待直到另一个线程释放信号量。如果有多个线程正在等待时,当一个线程释放信号量时,其中一个线程将获得它。释放信号量的线程不必是获取信号量的线程。

监视器就像公共厕所。只能一个人进入。他们锁定门以防止其他人进入,完成后再解锁。

信号量就像自行车租赁场所。他们有一定数量的自行车。如果您尝试租用一辆自行车,他们有一辆空闲的,那么您可以拿走它,否则您必须等待。当有人归还自行车时,其他人可以拿走它。如果您有自行车,则可以将其交给其他人归还---自行车租赁场所不在乎谁归还它,只要他们拿回自行车即可。


193
+1 用公共洗手间和自行车租赁场所做比喻非常好。现在我永远不会忘记它们之间的区别了。 - Drupad Panchal
4
你的回答似乎与http://stackoverflow.com/a/7336799/632951相矛盾。那么谁是正确的? - Pacerier
6
@Pacerier: 我是 :-) 唯一的矛盾之处在于高级/低级的问题。你可以用信号量构建监视器,只是不太整洁,恰恰因为监视器是比信号量更高级的结构。信号量只是一个带等待的计数器。我建议阅读《信号量小书》http://greenteapress.com/semaphores/ - Anthony Williams
3
我对只能使用信号量构建监视器的观点持怀疑态度。还有另一种方式可行,因此我们不能肯定地说监视器是比信号量更高级的实体。 - Kavish Dwivedi
6
是的,你可以从监视器构建信号量。你总是可以从高级对象中构建低级对象。高/低级别的区别在于能力和操作范围,而不是哪个可以用来构建另一个。 - Anthony Williams
显示剩余10条评论

11
以下解释实际上解释了监视器的wait()和signal()如何与信号量的P和V不同。
在监视器中,条件变量上的wait()和signal()操作类似于计数信号量上的P和V操作。 等待语句可以阻塞进程的执行,而信号语句可以导致另一个进程被解除阻塞。然而,它们之间存在一些差异。当进程执行P操作时,并不一定会阻塞该进程,因为计数信号量可能大于零。相反,当执行等待语句时,它总是会阻塞进程。当任务在信号量上执行V操作时,它要么解除等待该信号量的任务的阻塞状态,要么增加信号量计数器(如果没有任务需要解除阻塞)。另一方面,如果进程在没有其他进程需要解除阻塞的情况下执行信号语句,则对条件变量没有影响。信号量和监视器之间的另一个区别是通过V操作唤醒的用户可以立即恢复执行。相反,通过信号操作唤醒的用户只有在监视器解锁时才会重新启动。此外,与使用信号量的解决方案相比,监视器解决方案更具结构性,因为数据和过程封装在单个模块中,并且互斥由实现自动提供。

链接: here 了解更多信息。希望能对您有所帮助。


9
信号量允许多个线程(最多一定数量)访问共享对象。监视器允许互斥访问共享对象。 监视器 信号量

10
那么,监视器和互斥锁有何不同呢?互斥锁与信号量完全相同,但只允许一个线程同时访问关键区域。 - user919860
2
是的,监视器和互斥锁之间有什么区别? - Pacerier
2
值得注意的是,信号量并不控制对共享对象的访问,而是控制对共享资源的访问(该资源将包含多个对象)。 - Ayush
@xbonez:如果我们看一下java.util.ArrayList:它是一个对象还是多个对象的容器?嗯,它同时具备两者特性。那么,使用信号量来控制对它的访问是否合适?我会说:不合适。 - dma_k
在被接受的答案中,它本身就提到了Monitor正在实现互斥。请参见“监视器对象的成员函数或方法将强制执行互斥,因此在给定时间只有一个线程可以对该对象执行任何操作”。 - achoora

8

简短回答:

监视器:在监视器中一次只能控制一个线程执行(需要获取锁才能执行单个线程)。

信号量:用于保护共享资源的锁(需要获取锁才能访问资源)。


5

信号量(semaphore)是一种用于协调线程之间的信号传递机制。例如:一个线程正在从互联网下载文件,另一个线程正在分析这些文件。这是经典的生产者/消费者场景。当一个文件下载完成时,生产者会在信号量上调用 signal() 方法。消费者会在同一信号量上调用 wait() 方法以阻塞自身,直到接收到信号后才继续运行。如果在消费者调用 wait 时,信号量已经被唤醒了,则此次调用不会阻塞。多个线程可以等待同一个信号量,但每个信号只会解锁一个线程。

计数信号量(counting semaphore)会记录信号的数量。例如,如果生产者连续发出三个信号,wait() 可以被调用三次而不会阻塞。二元信号量(binary semaphore)不计数,只有“等待”和“唤醒”两个状态。

互斥锁(mutex,mutual exclusion lock)是由单个线程拥有的锁,只有获得锁的线程才能释放它。其他试图获取该锁的线程将被阻塞,直到当前所有者线程释放该锁。互斥锁本身并不锁定任何内容,它只是一个标志。但代码可以检查互斥锁的所有权,以确保一次只能有一个线程访问某个对象或资源。

监视器(monitor)是更高级别的构造,它使用底层互斥锁来确保对某个对象的线程安全访问。不幸的是,“监视器”这个词在不同的上下文和平台中有着不同的含义,但例如在Java中,“监视器”是与对象隐式关联的互斥锁,并且可以使用 synchronized 关键字调用。 synchronized 关键字可应用于类、方法或块,并确保一次只有一个线程可以执行该代码。


4

信号量:

在并发系统中使用计数器或标志来控制访问共享资源,这就需要使用信号量

例如:

  1. 为了让50个乘客获取任何剧院/公交车/火车/游乐设施/教室的50个座位(共享资源),可以使用一个计数器,并且只有在某人腾出座位时才允许新的乘客加入。
  2. 二进制标志指示任何浴室的空闲/占用状态。
  3. 交通信号灯是标志的好例子。它们通过调节道路上车辆的通过(共享资源)来控制流量。

标志仅显示资源的当前状态,不包含等待或运行对象在资源上的任何计数或其他信息。

监视器:

监视器通过与对该对象感兴趣的线程进行通信,要求它们获取访问权限或等待某些条件成为真来同步访问对象。

例如:

  1. 父亲可能会为女儿担任监视器,只允许她同时约会一个男孩。
  2. 学校老师使用警棍只允许一个孩子在班上发言。
  3. 最后是一个技术性的例子,通过线程对账户对象进行同步事务以维护其完整性。

我认为路口上的交通灯也是一个二进制标志:要么在一条道路上行驶,要么在正交道路上行驶(互斥),因此示例(3)与(2)相同。此外,我认为这些示例是信号量的边缘情况(平凡情况),可以使用监视器实现。在wikipedia中有更典型的示例。 - dma_k

3
当信号量用于保护关键区域时,信号量与被保护的数据之间没有直接的关系。这是信号量可能分散在代码周围且很容易忘记调用“wait”或“notify”的部分原因,在这种情况下,结果将是分别违反互斥性或永久锁定资源。
相比之下,使用监视器不会出现上述情况。监视器直接与数据相关联(封装了数据),并且由于监视器操作是原子操作,所以无法编写可以访问数据而不调用进入协议的代码。当监视器操作完成时,自动调用退出协议。
监视器具有内置的条件同步机制,形式为条件变量。如果条件未满足,进程必须等待,直到通知发生条件更改。当进程等待条件同步时,监视器实现会处理互斥问题,并允许另一个进程访问监视器。
摘自开放大学M362单元3“交互过程”课程材料。

除此之外,尽管信号量通常在某种语言中提供,并作为一种具有有限原子操作符的变量呈现在教科书上,但信号量实际上是监视器的特例-- 因为它是一种具有限制的原子算子的变量,这就是监视器的定义。认为信号量更“底层”的论点是站不住脚的。 - philipxy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接