二进制信号量和互斥量之间的区别

Nit*_*tin 787 glossary operating-system mutex semaphore binary-semaphore

二进制信号量和互斥量之间是否存在差异,或它们基本相同?

Ben*_*oit 674

它们不是一回事.它们用于不同的目的!
虽然两种类型的信号量都具有完整/空状态并使用相同的API,但它们的使用方式却截然不同.

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

Mutex信号量由接受它的任务"拥有".如果任务B尝试semGive当前由任务A持有的互斥锁,则任务B的调用将返回错误并失败.

互斥锁始终使用以下顺序:

  - SemTake
  - Critical Section
  - SemGive

这是一个简单的例子:

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

Binary Semaphore
Binary Semaphore解决了一个完全不同的问题:

  • 任务B等待发生某事(例如传感器被绊倒).
  • 传感器跳闸和中断服务程序运行.它需要通知行程的任务.
  • 任务B应该运行并对传感器跳闸采取适当的措施.然后回去等.

   Task A                      Task B
   ...                         Take BinSemaphore   <== wait for something
   Do Something Noteworthy
   Give BinSemaphore           do something    <== unblocks
Run Code Online (Sandbox Code Playgroud)

请注意,对于二进制信号量,B可以使用信号量和A来提供它.
同样,二进制信号量不保护资源不被访问.给予和获取信号量的行为从根本上是分离的.
对于相同的任务来说,通常对同一个二进制信号量的给予和接受没有多大意义.

  • 他们有不同的目的.Mutex用于独占访问资源.二进制信号量应该用于同步(即"嘿某人!发生了!").二元"给予者"只是告诉"接受者"他们正在等待的是谁. (103认同)
  • 那么互斥量信号量不是一个互斥量好吗?因为如果有人释放他实际上没有持有的锁,那就没有意义了. (11认同)
  • @Pacerier你的目的很混乱.互斥锁旨在保护关键区域.你是对的,使用二进制信号量是没有意义的.我会更新答案来解释每个目的. (5认同)
  • @Benoit所以我们可以说Mutex用于原子性和Binary Semaphore用于Ordering透视,因为任务B将等待任务A发出锁定信号,从而确保数据结构上的操作顺序? (4认同)
  • @abhi 这是查看互斥锁的好方法。但是,根据操作系统的不同,您可以有多个接收者在等待二进制信号量。在这种情况下,只有一个客户端会得到二进制 sem。其他人将等待下一个。接收顺序是否已知或有保证?取决于操作系统。 (2认同)
  • [信号量小书](http://greenteapress.com/semaphores/LittleBookOfSemaphores.pdf) 是有关这些问题的宝贵读物。 (2认同)
  • 但从这个解释可以看出,在语义上,它在某种程度上是完全一样的。典型的使用场景不同,实现的一些技术细节可能不同,例如从另一个线程解锁/发出信号的可能性。但除此之外都是一样的——程序只是等待某些事情继续执行,而程序的另一部分可以使“某事”发生。 (2认同)
  • 这个答案可能有用,但我不认为这实际上回答了问题。我没有看到任何关于互斥体和二进制信号量如何以不同的方式实现其不同的预期目标的信息。也许我错过了什么。 (2认同)

dli*_*sin 441

厕所的例子是一个令人愉快的比喻:

互斥:

是厕所的关键.一个人可以拥有钥匙 - 占用厕所 - 当时.完成后,该人员将(释放)密钥提供给队列中的下一个人.

正式说:"互斥锁通常用于序列化对一部分重入代码的访问,这些代码不能由多个线程同时执行.互斥对象只允许一个线程进入受控部分,强制其他线程尝试访问该部分要等到第一个线程退出该部分." 参考:Symbian开发人员库

(互斥体实际上是一个值为1的信号量.)

信号:

是免费相同的厕所钥匙的数量.例如,我们说有四个带有相同锁和钥匙的马桶.信号量计数 - 键数 - 在开始时设置为4(所有四个厕所都是免费的),然后计数值随着人们的进入而减少.如果所有厕所都已满,即.没有剩余的自由键,信号量计数为0.现在,当eq.一个人离开厕所,信号量增加到1(一个自由键),并给予队列中的下一个人.

正式地说:"信号量将共享资源的同时用户数量限制为最大数量.线程可以请求访问资源(递减信号量),并且可以发信号通知他们已经完成了使用资源(递增信号量). " 参考:Symbian开发人员库

  • ...但这是关于互斥锁与计数信号量.问的问题是关于二元的. (225认同)
  • 虽然大卫所说的是正确的,但它不是问题的答案.Mladen Jankovic的回答是问题的答案,其中有人要区分"二元信号量"和"互斥量". (22认同)
  • 不幸的是,这个错误的答案比@Benoit的最佳答案更多 (12认同)
  • 这个答案是误导性的.应该只与Binary Semaphore比较. (5认同)
  • 这也演示了使用计数信号量来保护共享资源的问题:如果密钥确实相同,并且使用密钥对厕所进行了解锁,并且没有其他机制可以分配小隔间使用量,则:(1)第一种用户解锁,进入并开始使用第一个隔间。(2)下一个用户解锁,进入并开始使用第一个隔间... (3认同)
  • 换句话说:二进制信号量与互斥量相同。因在多个段落中提供单线信息而被低估。而且甚至没有解决所问的问题。 (3认同)
  • 所以你是说如果我搞砸了互斥锁,我可能会和陌生人一起在浴室里穿过溪流!? (3认同)
  • 我没有看到问题 - 二进制信号量只是一个计数信号量,其中最大计数为1.这个类比仍然非常适用.区别在于信号量保持计数. (2认同)
  • @JacobRitchie 问题在于“互斥锁实际上是值为 1 的信号量”的语句,但事实并非如此。ThreadA 并且只有 ThreadA 可以增加(并因此释放)它减少的互斥锁,而 ThreadB 可以增加由 ThreadA 减少的 binSemaphore,这也恰好是问题的答案。 (2认同)

Mla*_*vić 426

Mutex只能由获取它的线程释放,而您可以从任何其他线程(或进程)发出信号量信号,因此信号量更适合某些同步问题,如producer-consumer.

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

  • @ warl0ck请参阅http://stackoverflow.com/a/5492499/385064'Pthreads有3种不同的互斥锁:快速互斥锁,递归互斥锁和错误检查互斥锁.您使用了一个快速互斥锁,出于性能原因,它不会检查此错误.如果你在Linux上使用错误检查互斥锁,你会发现你得到了你期望的结果. (43认同)
  • `Mutex只能通过获取它的线程发布` - 我只是尝试使用一个简单的基于pthread_mutex的程序,一个线程可以解锁锁定在主线程中的互斥锁 (32认同)
  • @ warl0ck根据pthread_mutex_lock的手册页http://linux.die.net/man/3/pthread_mutex_lock:"如果互斥锁类型为PTHREAD_MUTEX_ERRORCHECK,则应提供错误检查....如果线程试图解锁a未锁定的互斥锁或解锁的互斥锁,应返回错误." (11认同)
  • 在我们的代码中,我们也使用互斥锁来实现同步目的。锁定互斥锁的线程再次尝试锁定互斥锁。然后它进入阻塞状态。我们所看到的是,我们能够从另一个线程解锁它。从而实现两者之间的同步。我们仅使用 posix 标准。因此互斥量和二进制信号量之间的主要区别似乎很模糊。 (3认同)

tek*_*eki 147

关于这个主题的好文章:

从第2部分:

互斥体类似于二进制信号量的原理,有一个显着的区别:所有权原则.所有权是一个简单的概念,当任务锁定(获取)互斥锁时,它只能解锁(释放)它.如果任务尝试解锁互斥锁,它未锁定(因此不拥有),则会遇到错误情况,最重要的是,互斥锁未解锁.如果互斥对象没有所有权,那么与它所称的无关,它不是互斥体.

  • +1 敌人优秀的文章链接。用“它是什么”和“它做什么”解释信号量和互斥体的最佳文章 https://computing.llnl.gov/tutorials/pthreads/ 我使用这篇文章作为我的幕后参考,其中从技术上讲,确实解释了有关互斥体/条件语句以及构建在其顶部的其他构造(如信号量/屏障/读写器)的所有内容,但没有明确和简洁地说明构造所面临的问题。简而言之就是参考。:) (3认同)

Hem*_*ant 96

由于上述答案都没有解决这个混乱,所以这里有一个让我感到困惑的答案.

严格地说,互斥锁是一种用于同步对资源的访问的锁定机制.只有一个任务(可以是基于操作系统抽象的线程或进程)可以获取互斥锁.这意味着将拥有与互斥锁相关的所有权,只有所有者才能释放锁(互斥锁).

信号量是信号机制("我做完了,你可以继续"的信号).例如,如果您正在移动设备上监听歌曲(假设它是一项任务),同时您的朋友打电话给您,则会触发中断,中断服务程序(ISR)将通知呼叫处理任务唤醒.

资料来源:http://www.geeksforgeeks.org/mutex-vs-semaphore/


Var*_*ani 41

  • 根据定义,Mutex用于序列化对一部分可重入代码的访问,这些代码不能由多个线程同时执行.

  • 根据定义,信号量将共享资源的并发用户数限制为最大数量

  • 信号量可以是互斥量,但互斥量永远不会是信号量.这只是意味着二进制信号量可以用作Mutex,但是Mutex永远不会展示信号量的功能.

  • 信号量和Mutex(至少是最新的内核)本质上都是非递归的.
  • 没有人拥有信号量,而Mutex是拥有的,所有者对它们负责.这是与调试角度的重要区别.
  • 在Mutex的情况下,拥有Mutex的线程负责释放它.但是,在信号量的情况下,不需要这种情况.任何其他线程都可以通过使用smps来函数释放信号量(function.e_ot)

  • 另一个对开发人员很重要的区别是,信号量是系统范围的,并且保留在文件系统上的文件形式,除非另外清理.Mutex是流程范围的,并在流程退出时自动清理.

  • 信号量的本质使得它们可以在同步相关和不相关的进程以及线程之间使用它们.Mutex只能用于线程之间的同步,最多只能用于相关进程之间(最新内核的pthread实现带有一个允许在相关进程之间使用Mutex的功能).
  • 根据内核文档,与信号量相比,Mutex更轻.这意味着与具有Mutex的程序相比,具有信号量使用的程序具有更高的内存占用.
  • 从使用角度来看,与信号量相比,Mutex具有更简单的语义.


小智 40

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

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

因此,可以看到互斥体作为从任务传递到任务的令牌和信号量作为流量红灯(它某人发出信号,表明它可以继续).


Con*_*lls 22

在理论层面,它们在语义上没有区别.您可以使用信号量实现互斥锁,反之亦然(请参阅此处的示例).在实践中,实施是不同的,它们提供略有不同的服务.

实际差异(就其周围的系统服务而言)是互斥体的实现旨在成为更轻量级的同步机制.在oracle中,互斥体被称为锁存器,信号量被称为等待.

在最低级别,他们使用某种原子测试和设置机制.这将读取内存位置的当前值,计算某种条件,并在单个指令中的该位置写出一个无法中断的值.这意味着您可以获取互斥锁并进行测试以查看是否有其他人在您之前拥有它.

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

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.
Run Code Online (Sandbox Code Playgroud)

当我们完成执行受保护的代码(称为临界区)时,我们只需将互斥量值设置为零或任何"清除"的方式.如果多个任务正在尝试获取互斥锁,则在释放互斥锁后恰好安排的下一个任务将获得对该资源的访问权限.通常,您将使用互斥锁来控制同步资源,其中仅在非常短的时间段内需要独占访问,通常是为了更新共享数据结构.

信号量是一种同步数据结构(通常使用互斥锁),它具有计数和一些系统调用包装,它们与调度程序交互的程度比互斥库更深.信号量递增和递减,用于阻止任务,直到其他东西准备好.有关此的简单示例,请参阅生产者/消费者问题.信号量初始化为某个值 - 二进制信号量只是信号量初始化为1的特殊情况.发布信号量可以唤醒等待进程.

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

(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.
Run Code Online (Sandbox Code Playgroud)

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

编辑:正如埃文正确指出的那样,自旋锁将减慢单个处理器的速度.您只能在多处理器盒上使用自旋锁,因为在单个处理器上,当另一个任务正在运行时,持有互斥锁的进程将永远不会重置它.自旋锁只适用于多处理器架构.

  • 我不认为用自旋锁实现互斥体是常见的做法。在 Uni-proc 机器上,这对于性能来说绝对是糟糕的。 (2认同)

Pra*_*kla 18

虽然互斥和信号量被用作同步原语,但它们之间存在很大差异.在互斥锁的情况下,只有锁定或获取互斥锁的线程才能解锁它.在信号量的情况下,等待信号量的线程可以由不同的线程发信号通知.某些操作系统支持在进程之间使用互斥锁和信号量.通常用法是在共享内存中创建.


Sum*_*aik 15

Mutex:假设我们有关键部分线程T1想要访问它,然后它遵循以下步骤.T1:

  1. 使用关键部分
  2. 开锁

二进制信号量:它基于信令等待和信号工作.等待(s)将"s"值减少一个通常"s"值用值"1"初始化,信号(s)将"s"值增加1.如果"s"值为1则表示没有人使用临界区,当值为0表示临界区正在使用中.假设线程T2正在使用临界区,那么它遵循以下步骤.T2:

  1. wait(s)//最初s值在调用之后等于它的值减1,即0
  2. 使用关键部分
  3. signal(s)//现在s值增加,变为1

Mutex和Binary信号量之间的主要区别在于Mutext如果线程锁定临界区然后它必须解锁临界区而没有其他线程可以解锁它,但是在Binary信号量的情况下如果一个线程使用wait(s)函数锁定临界区然后值s变为"0"并且没有人可以访问它,直到"s"的值变为1但是假设某些其他线程调用信号然后"s"的值变为1并且它允许其他功能使用临界区.因此在Binary信号量线程中没有所有权.


小智 11

在Windows上,互斥锁和二进制信号量之间存在两个不同之处:

  1. 互斥锁只能由拥有所有权的线程释放,即先前调用Wait函数的线程(或者在创建它时获得所有权).任何线程都可以释放信号量.

  2. 线程可以在互斥锁上重复调用等待函数而不会阻塞.但是,如果在二进制信号量上调用等待函数两次而不释放其间的信号量,则线程将阻塞.

  • 好答案.在#2中,您正在描述递归互斥锁 - 并非所有互斥锁都必须是递归的.例如,http://www.cs.wustl.edu/~schmidt/ACE.FAQ.html#Q14 (4认同)

小智 10

你显然使用互斥锁来锁定一个线程中的数据,同时被另一个线程访问.假设您刚刚调用lock()并正在访问数据.这意味着您不希望任何其他线程(或相同线程代码的另一个实例)访问由同一个互斥锁锁定的相同数据.也就是说,如果在不同的线程实例上执行相同的线程代码,则命中锁,然后lock()应该阻止那里的控制流.这适用于使用不同线程代码的线程,该线程代码也访问相同的数据,并且也被同一个互斥锁锁定.在这种情况下,您仍然在访问数据,并且您可能需要另外15秒来达到互斥锁解锁(以便在互斥锁中被阻止的另一个线程将解锁并允许控制访问数据).您是否不惜一切代价允许另一个线程解锁相同的互斥锁,反过来又允许已经在互斥锁中等待(阻塞)的线程解除阻塞并访问数据?希望你能得到我在这里说的话?根据,同意普遍定义!,

  • 用"互斥"这种情况不可能发生.没有其他线程可以解锁线程中的锁
  • 使用"二进制信号量"可能会发生这种情况.任何其他线程都可以解锁线程中的锁

所以,如果你非常特别使用二进制信号量而不是互斥量,那么你应该非常小心地"确定"锁定和解锁.我的意思是,每次锁定的每个控制流都应该打一个解锁电话,也不应该有任何"第一次解锁",而应该始终是"第一次锁定".


小智 10

互斥锁用于"锁定机制".一次一个进程可以使用共享资源

信号量用于"信令机制",如"我完成了,现在可以继续"


Sau*_*nha 9

神话:

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

关键点:

•线程可以获取多个锁(Mutex).

•只有当互斥锁具有递归互斥锁时,互斥锁才能锁定多次,此处锁定和解锁互斥锁应该相同

•如果已锁定互斥锁的线程再次尝试锁定互斥锁,则它将进入该互斥锁的等待列表,从而导致死锁.

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

•由于与之相关的保护协议,互斥锁的运行成本很高.

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


小智 8

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

一个信号量控制对资源的共享池.它向Wait()提供操作,直到池中的一个资源变为可用,并将Signal()提供给池.

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

因此,信号量是一种比Mutex更高级别的抽象.可以使用信号量实现互斥锁,但不能相反.


小智 6

修改过的问题是 - "Linux"中的互斥锁和"二进制"信号量有什么区别?

Ans:以下是差异 - i)范围 - 互斥体的范围在创建它的进程地址空间内,并用于线程同步.信号量可以跨进程空间使用,因此可以用于进程间同步.

ii)Mutex比信号量轻,速度快.Futex甚至更快.

iii)互斥锁可以被同一个线程多次成功获取,条件是它应该释放相同的次数.尝试获取的其他线程将阻止.而在信号量的情况下,如果相同的进程再次尝试获取它,则它会阻塞,因为它只能被获取一次.

  • i) 错误。ii) 来源?iii) 这要看情况。 (2认同)

bud*_*ddy 6

Binary Semaphore和Mutex之间的区别:OWNERSHIP: 信号量甚至可以从非当前所有者发出信号(发布).这意味着您可以简单地从任何其他线程发布,但您不是所有者.

信号量是一个正在处理的公共财产,它可以简单地由非所有者线程发布.请用粗体字母标记这个区别,这意味着很多.


小智 5

Mutex致力于阻止关键区域,但Semaphore依赖于计数.


小智 5

http://www.geeksforgeeks.org/archives/9102 详细讨论.

Mutex是用于同步对资源的访问的锁定机制. Semaphore是信号机制.

如果他/她想使用二进制信号量代替互斥量,那么它应该由程序员完成.