二进制信号量和互斥量之间有区别吗?或者它们本质上是相同的?


当前回答

除了互斥对象有一个所有者之外,这两个对象还可以针对不同的用途进行优化。互斥锁被设计为只保留很短的时间;违反这一点会导致糟糕的性能和不公平的调度。例如,一个正在运行的线程可能被允许获取一个互斥量,即使另一个线程已经被阻塞在这个线程上。信号量可以提供更多的公平性,或者可以使用几个条件变量强制实现公平性。

其他回答

互斥锁只能由获得它的线程释放。 二进制信号量可以由任何线程(或进程)发出信号。

因此,信号量更适合于一些同步问题,如生产者-消费者。

在Windows上,二进制信号量更像事件对象而不是互斥对象。

神话:

一些文章说“二进制信号量和互斥量是相同的”或“值为1的信号量是互斥量”,但基本的区别是互斥量只能由获得它的线程释放,而你可以从任何其他线程发出信号量

重点:

一个线程可以获得多个锁(互斥锁)。

只有递归互斥锁才能被锁多次,这里的锁和锁应该是一样的

•如果一个线程已经锁定了一个互斥锁,试图再次锁定互斥锁,它将进入该互斥锁的等待列表,这将导致死锁。

二进制信号量和互斥量相似但不相同。

互斥是昂贵的操作,因为与它相关的保护协议。

互斥的主要目的是实现对资源的原子访问或锁定

它们不是一回事。它们有不同的用途! 虽然这两种类型的信号量都有一个满/空状态,并且使用相同的API,但它们的用法非常不同。

互斥信号量 互斥信号量用于保护共享资源(数据结构、文件等)。

互斥信号量由接收它的任务“拥有”。如果Task B尝试semGive一个当前由Task a持有的互斥锁,Task B的调用将返回一个错误并失败。

互斥对象总是使用以下顺序:

  - SemTake
  - Critical Section
  - SemGive

这里有一个简单的例子:

  Thread A                     Thread B
   Take Mutex
     access data
     ...                        Take Mutex  <== Will block
     ...
   Give Mutex                     access data  <== Unblocks
                                  ...
                                Give Mutex

二进制信号量 二进制信号量解决了一个完全不同的问题:

任务B被挂起等待某些事情发生(例如传感器被绊倒)。 传感器跳闸和中断服务程序运行。它需要通知任务的行程。 任务B应运行并对传感器跳闸采取适当的操作。然后继续等待。


   Task A                      Task B
   ...                         Take BinSemaphore   <== wait for something
   Do Something Noteworthy
   Give BinSemaphore           do something    <== unblocks

注意,对于二进制信号量,B获取信号量,a给出信号量是可以的。 同样,二进制信号量不能保护资源不被访问。信号量的给予和获取从根本上是分离的。 对于同一个任务来说,对同一个二进制信号量的给予和获取通常没有什么意义。

互斥锁控制对单个共享资源的访问。它提供了获取()对资源的访问并在完成后释放()资源的操作。

信号量控制对共享资源池的访问。它提供Wait()操作,直到池中的一个资源可用,并提供Signal()操作,当它返回池时。

当一个信号量保护的资源数量大于1时,它被称为计数信号量。当它控制一个资源时,它被称为布尔信号量。布尔信号量相当于互斥量。

因此,信号量是比互斥量更高级别的抽象。互斥锁可以用信号量来实现,但不能用信号量来实现。

在Windows上,互斥量和二进制信号量之间有两个区别:

互斥锁只能由拥有所有权的线程释放,即之前调用Wait函数的线程(或在创建互斥锁时获得所有权的线程)。任何线程都可以释放信号量。 线程可以在互斥锁上重复调用等待函数而不会阻塞。但是,如果你在一个二进制信号量上调用了两次等待函数,而中间没有释放信号量,线程就会阻塞。