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


当前回答

互斥锁用于“锁定机制”。每次只有一个进程可以使用共享资源

信号量用于“信号机制” 比如“我完成了,现在可以继续了”

其他回答

它们不是一回事。它们有不同的用途! 虽然这两种类型的信号量都有一个满/空状态,并且使用相同的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给出信号量是可以的。 同样,二进制信号量不能保护资源不被访问。信号量的给予和获取从根本上是分离的。 对于同一个任务来说,对同一个二进制信号量的给予和获取通常没有什么意义。

互斥量和二进制信号量是相同的用法,但实际上,它们是不同的。

对于互斥锁,只有锁定了它的线程才能解锁它。如果有其他线程来锁定它,它将等待。

对于信号电话来说,情况就不是这样了。信号量没有与特定的线程ID绑定。

在理论层面上,它们在语义上并无不同。您可以使用信号量实现互斥量,反之亦然(参见这里的示例)。在实践中,实现是不同的,它们提供的服务也略有不同。

实际的区别(就围绕它们的系统服务而言)在于互斥锁的实现旨在成为一种更轻量级的同步机制。在oracle语言中,互斥锁被称为锁存器,而信号量被称为等待。

在最低级别,他们使用某种原子测试和设置机制。它读取内存位置的当前值,计算某种条件,并在一条不能中断的指令中写入该位置的值。这意味着您可以获得一个互斥锁,并测试是否有人在您之前拥有它。

典型的互斥量实现有一个进程或线程执行test-and-set指令,并评估是否有其他东西设置了互斥量。这里的关键点是与调度程序没有交互,因此我们不知道(也不关心)谁设置了锁。然后,我们要么放弃我们的时间片,并在任务重新调度时再次尝试它,要么执行自旋锁。自旋锁是这样一种算法:

Count down from 5000:
     i. Execute the test-and-set instruction
    ii. If the mutex is clear, we have acquired it in the previous instruction 
        so we can exit the loop
   iii. When we get to zero, give up our time slice.

当我们完成执行受保护的代码(称为临界区)时,我们只需将互斥量的值设置为零或其他表示“清除”的值。如果有多个任务试图获取互斥量,那么下一个计划在互斥量释放后的任务将获得对资源的访问权。通常情况下,您可以使用互斥来控制同步资源,在这种资源中,只需要在很短的时间内对其进行独占访问,通常是对共享数据结构进行更新。

A semaphore is a synchronised data structure (typically using a mutex) that has a count and some system call wrappers that interact with the scheduler in a bit more depth than the mutex libraries would. Semaphores are incremented and decremented and used to block tasks until something else is ready. See Producer/Consumer Problem for a simple example of this. Semaphores are initialised to some value - a binary semaphore is just a special case where the semaphore is initialised to 1. Posting to a semaphore has the effect of waking up a waiting process.

一个基本的信号量算法如下所示:

(somewhere in the program startup)
Initialise the semaphore to its start-up value.

Acquiring a semaphore
   i. (synchronised) Attempt to decrement the semaphore value
  ii. If the value would be less than zero, put the task on the tail of the list of tasks waiting on the semaphore and give up the time slice.

Posting a semaphore
   i. (synchronised) Increment the semaphore value
  ii. If the value is greater or equal to the amount requested in the post at the front of the queue, take that task off the queue and make it runnable.  
 iii. Repeat (ii) for all tasks until the posted value is exhausted or there are no more tasks waiting.

在二进制信号量的情况下,两者之间的主要实际区别是围绕实际数据结构的系统服务的性质。

编辑:正如evan正确地指出的那样,自旋锁会降低单个处理器的速度。你只能在多处理器上使用自旋锁,因为在单处理器上,持有互斥锁的进程永远不会在另一个任务运行时重置它。自旋锁只在多处理器架构上有用。

修改问题是-互斥量和“二进制”信号量在“Linux”中的区别是什么?

答:以下是它们的区别 i)作用域——互斥锁的作用域在创建它的进程地址空间内,用于线程同步。而信号量可以跨进程空间使用,因此它可以用于进程间同步。

ii)互斥量是轻量级的,比信号量更快。Futex甚至更快。

iii)同一线程可以成功多次获得互斥锁,条件是互斥锁释放次数相同。其他线程试图获取将阻塞。而对于信号量,如果同一个进程试图再次获取它,它会阻塞,因为它只能获得一次。

它们的同步语义非常不同:

互斥对象允许对给定资源的序列化访问,即多个线程等待一个锁,一次一个,正如前面所说,线程拥有锁,直到锁完成:只有这个特定的线程可以解锁它。 二进制信号量是一个值为0和1的计数器:任务阻塞在它上,直到任何任务执行sem_post。信号量宣布资源可用,并提供等待机制,直到发出可用信号。

因此,可以将互斥锁视为在任务之间传递的令牌,将信号量视为交通红灯(它向某人发出信号,表示可以继续进行)。