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

二进制信号量和互斥量之间是否有区别,还是基本相同?

他们不是一回事。 他们用于不同的目的!
虽然这两种信号量都具有完全/空的状态并使用相同的API,但它们的使用情况却非常不同。

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

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

互斥量总是使用以下顺序:

   -  SemTake
   - 关键部分
   -  SemGive 

这是一个简单的例子:

  穿线B
   采取互斥
     访问数据
      ...采取互斥<==将阻止
      ...
   给互斥体访问数据<==解锁
                                   ...
                                给互斥体

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

  • 任务B被挂起等待发生事件(例如传感器被触发)。
  • 传感器跳闸和中断服务例程运行。 它需要通知旅行的任务。
  • 任务B应运行,并采取适当的措施传感器旅行。 然后回去等待。
Task A Task B ... Take BinSemaphore <== wait for something Do Something Noteworthy Give BinSemaphore do something <== unblocks 

请注意,对于二进制信号量,B采取信号量和A给它是可以的。
同样,二进制信号量不会保护资源不被访问。 给与信号量的行为从根本上是分离的。
对于同样的任务,给予和采用相同的二进制信号通常是没有意义的。

互斥量只能由已经获得它的线程释放,而你可以从任何其他线程(或进程)发出信号量,所以信号量更适合生产者 – 消费者之类的一些同步问题。

在Windows上,二进制信号比互斥体更像事件对象。

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

互斥:

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

正式地说:“互斥锁通常用来串行访问一段不能同时被多个线程执行的重入代码,一个互斥对象只允许一个线程进入一个受控节,强制其他线程尝试访问该部分要等到第一个线程退出该部分。“ 参考:Symbian开发人员库

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

信号:

是免费的相同的马桶钥匙的数字。 比如说,我们有四个带有相同的锁和钥匙的洗手间。 信号计数 – 密钥计数 – 在开始时设置为4(所有四个厕所都是免费的),然后计数值随着人们进入而递减。如果所有的厕所都满了, 没有空闲密钥,信号计数为0.现在,当等式 一个人离开厕所,信号量增加到1(一个自由键),并给予排队中的下一个人。

正式地说:“一个信号量限制共享资源的并发用户数达到最大值,线程可以请求访问资源(递减信号量),并可以表示他们已经完成使用资源(增加信号量)。 “ 参考:Symbian开发人员库

好主题的文章:

  • MUTEX VS. SEMAPHORES – 第1部分:SEMAPHORES
  • MUTEX VS. SEMAPHORES – 第2部分:MUTEX
  • MUTEX VS. SEMAPHORES – 第3部分(最后部分):相互排斥问题

从第2部分:

互斥量与二元信号量的原理类似,有一个显着的区别:所有权原则。 所有权是一个简单的概念,当一个任务locking(获取)一个互斥锁,只有它可以解锁(释放)它。 如果一个任务试图解锁它没有locking的互斥体(因此不拥有),则会遇到错误情况,最重要的是互斥体未被解锁。 如果互斥对象不具有所有权,则与所谓的无关,不是互斥对象。

由于上述答案都没有解决混淆,所以这是一个清除了我的困惑。

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

信号量是信号机制 (“我做完了,你可以进行”这种信号)。 例如,如果您正在手机上收听歌曲(假定为一项任务),同时您的朋友打电话给您,则会触发一个中断,中断服务例程(ISR)将通过该中断向唤醒的呼叫处理任务发出信号。

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

他们的同步语义是非常不同的:

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

这样的人可以看到一个互斥信号作为从任务传递给任务的信号和信号量,如交通红灯(它表示可以继续)。

在理论层面上,它们在语义上没有区别。 你可以使用信号量来实现一个互斥量,反之亦然(参见这里的例子)。 在实践中,实现是不同的,它们提供的服务略有不同。

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

在最底层,他们使用某种primefacestesting和设置机制。 这读取一个内存位置的当前值,计算某种条件,并在一个不能中断的单个指令中写出该位置的值。 这意味着你可以获得一个互斥体并testing是否有其他人在你面前。

一个典型的互斥体实现有一个进程或线程执行testing和设置指令,并评估是否有其他设置互斥体。 这里的一个关键点是与调度程序没有交互,所以我们不知道(也不关心)谁设置了锁。 然后,我们要么放弃我们的时间片,并在任务重新计划或执行旋转locking时再次尝试。 自旋锁是一种algorithm,如:

 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. 

当我们完成执行我们的受保护的代码(称为临界区 )时,我们只需将互斥量的值设置为零,或者任何方法“清除”。 如果多个任务试图获取互斥量,那么发布互斥量之后发生的下一个任务将访问资源。 通常情况下,您可以使用互斥体来控制同步资源,其中只需要非常短的时间就可以使用独占访问,通常是对共享数据结构进行更新。

信号量是一个同步的数据结构(通常使用一个互斥量),它具有一个计数和一些系统调用包装,它们与调度程序相互作用的深度比互斥量库要多。 信号被递增和递减,并被用来阻塞任务,直到其他东西准备好。 见生产者/消费者问题一个简单的例子。 信号量被初始化为一定的值 – 二进制信号量仅仅是信号量被初始化为1的特殊情况。发送到信号量具有唤醒等待过程的效果。

基本的信号量algorithm如下所示:

 (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. 

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

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

尽pipe互斥和信号被用作同步原语,但它们之间有很大的区别。 在互斥体的情况下,只有locking或获取互斥锁的线程才能解锁它。 在信号量的情况下,等待信号量的线程可以由不同的线程发信号通知。 一些操作系统支持在进程间使用互斥锁和信号量。 通常使用在共享内存中创build。

一个信号量可以是一个互斥量,但一个互斥量不可能是信号量。 这只是意味着可以使用二进制信号量
作为互斥体,但互斥体永远不能展现信号量的function。
2.信号量和Mutex(至less是最新的内核)本质上都是非recursion的。
3.没有人拥有信号量,而互斥量是拥有的,而拥有者则对其负责。 从debugging的angular度来看,这是一个重要的区别。
4.如果互斥体,拥有互斥体的线程负责释放它。 但是,在信号量的情况下,这个条件是不需要的。 任何其他线程都可以通过使用smps(function.e_ot)来释放信号量,
5.根据定义,Mutex用于序列化对一段不能同时由多个线程执行的重入代码的访问。 根据定义,信号量将共享资源的并发用户数限制在最大值
6.另一个与开发人员不同的地方是信号量是系统范围的,除非另外清理,否则它们将保持文件系统上的文件forms。 互斥进程在整个stream程中,并在stream程退出时自动清理。
7.信号量的本质使得它们可以在同步相关和不相关进程以及线程间使用它们。 互斥锁只能用于线程之间的同步,并且最多可以在相关进程之间进行同步(最新内核的pthread实现带有允许在相关进程之间使用互斥体的function)。
8.根据内核文档,与信号量相比,互斥量较小。 这意味着,与具有互斥锁的程序相比,使用信号量的程序具有更高的内存占用量。
9.从使用的angular度来看,与信号量相比,互斥量具有更简单的语义。

您显然使用互斥体来locking一个线程中的数据同时被另一个线程访问。 假设你刚才调用了lock()并且正在访问数据的过程中。 这意味着你不希望任何其他线程(或相同的线程代码的另一个实例)访问相同的互斥锁相同的数据。 也就是说,如果是在不同的线程实例上获得相同的线程代码,则会触发该锁,那么lock()应该会阻塞那里的控制stream。 这适用于使用不同线程代码的线程,该代码也访问相同的数据,并且也被相同的互斥锁locking。 在这种情况下,您仍在访问数据,您可能需要15秒才能到达互斥锁(这样,互斥锁中被阻塞的另一个线程将会解锁并允许控件访问数据)。 你会不惜任何代价允许另一个线程来解锁相同的互斥锁,并反过来,允许已经在互斥锁中等待(阻塞)的线程解锁并访问数据? 希望你明白我在这里说的吗? 按照约定普遍的定义!

  • 与“互斥体”这不可能发生。 没有其他线程可以解锁你的线程中的锁
  • 与“二进制信号量”这可能会发生。 任何其他线程都可以解锁线程中的锁

所以,如果你非常关心使用二进制信号而不是互斥,那么你应该非常小心地“locking”locking和解锁。 我的意思是每一个控制stream都会触发一个解锁的调用,也不应该有任何“第一次解锁”,而应该总是“第一次locking”。

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

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

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

  1. 一个互斥体只能由拥有所有权的线程释放,也就是之前称为Wait函数的线程(或者在创build时拥有所有权的线程)。 信号量可以被任何线程释放。

  2. 一个线程可以在一个互斥体上重复地调用一个等待函数而不会阻塞。 但是,如果在二进制信号量上调用两次等待函数而不释放信号量,则该线程将被阻塞。

神话:

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

关键点:

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

•一个互斥锁可以被locking不止一次,只要它是一个recursion互斥锁,这里locking和解锁互斥量应该是相同的

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

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

•由于与之相关的保护协议,互斥是昂贵的操作。

•互斥锁的主要目的是实现primefaces访问或locking资源

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

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

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

因此信号量比互斥量要高一级的抽象。 一个互斥量可以用一个信号量来实现,但是不能用另一种方式来实现。

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

答:以下是不同之处 – i)范围 – 互斥体的范围在创build它的进程地址空间中,用于线程的同步。 而信号量可以跨进程空间使用,因此它可以用于进程间同步。

ii)互斥量比信号量更轻量更快。 互斥更快。

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

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

Mutex是用于同步对资源的访问的locking机制。 Semaphore是信号机制。

如果他/她想使用二进制信号代替互斥量的话,那么它就是程序员。

二元信号量与互斥量之间的差异:所有权: 即使是非当前所有者,信号量也可以发送(张贴)。 这意味着你可以简单地从任何其他线程发布,虽然你不是所有者。

信号量是一个正在进行的公共财产,它可以简单地由非所有者线程发布。 请用大写字母标出这个差异,这意味着很多。

互斥工作阻塞关键区域,但信号量工作。

除了互斥锁拥有者之外,这两个对象可以针对不同的用途进行优化。 互斥体的devise只能在短时间内进行; 违反这个规定可能导致不良的performance和不公平的调度。 例如,一个正在运行的线程可能被允许获取一个互斥量,即使另一个线程已经被阻塞了。 信号量可以提供更多的公平性,或者可以使用多个条件variables强制公平。

在Windows中,区别如下。 MUTEX:成功执行等待的进程必须执行一个信号 ,反之亦然。 二进制SEMAPHORES:不同的进程可以在信号量上执行等待信号操作。

上述职位后,这个概念很清楚。 但是还有一些萦绕不去的问题。 所以,我写了这一小段代码。

当我们试图给一个信号而没有采取它时,它就会通过。 但是,当你尝试不用服用互斥体时,就会失败。 我在Windows平台上testing了这个。 启用USE_MUTEX使用MUTEX运行相同的代码。

 #include <stdio.h> #include <windows.h> #define xUSE_MUTEX 1 #define MAX_SEM_COUNT 1 DWORD WINAPI Thread_no_1( LPVOID lpParam ); DWORD WINAPI Thread_no_2( LPVOID lpParam ); HANDLE Handle_Of_Thread_1 = 0; HANDLE Handle_Of_Thread_2 = 0; int Data_Of_Thread_1 = 1; int Data_Of_Thread_2 = 2; HANDLE ghMutex = NULL; HANDLE ghSemaphore = NULL; int main(void) { #ifdef USE_MUTEX ghMutex = CreateMutex( NULL, FALSE, NULL); if (ghMutex == NULL) { printf("CreateMutex error: %d\n", GetLastError()); return 1; } #else // Create a semaphore with initial and max counts of MAX_SEM_COUNT ghSemaphore = CreateSemaphore(NULL,MAX_SEM_COUNT,MAX_SEM_COUNT,NULL); if (ghSemaphore == NULL) { printf("CreateSemaphore error: %d\n", GetLastError()); return 1; } #endif // Create thread 1. Handle_Of_Thread_1 = CreateThread( NULL, 0,Thread_no_1, &Data_Of_Thread_1, 0, NULL); if ( Handle_Of_Thread_1 == NULL) { printf("Create first thread problem \n"); return 1; } /* sleep for 5 seconds **/ Sleep(5 * 1000); /*Create thread 2 */ Handle_Of_Thread_2 = CreateThread( NULL, 0,Thread_no_2, &Data_Of_Thread_2, 0, NULL); if ( Handle_Of_Thread_2 == NULL) { printf("Create second thread problem \n"); return 1; } // Sleep for 20 seconds Sleep(20 * 1000); printf("Out of the program \n"); return 0; } int my_critical_section_code(HANDLE thread_handle) { #ifdef USE_MUTEX if(thread_handle == Handle_Of_Thread_1) { /* get the lock */ WaitForSingleObject(ghMutex, INFINITE); printf("Thread 1 holding the mutex \n"); } #else /* get the semaphore */ if(thread_handle == Handle_Of_Thread_1) { WaitForSingleObject(ghSemaphore, INFINITE); printf("Thread 1 holding semaphore \n"); } #endif if(thread_handle == Handle_Of_Thread_1) { /* sleep for 10 seconds */ Sleep(10 * 1000); #ifdef USE_MUTEX printf("Thread 1 about to release mutex \n"); #else printf("Thread 1 about to release semaphore \n"); #endif } else { /* sleep for 3 secconds */ Sleep(3 * 1000); } #ifdef USE_MUTEX /* release the lock*/ if(!ReleaseMutex(ghMutex)) { printf("Release Mutex error in thread %d: error # %d\n", (thread_handle == Handle_Of_Thread_1 ? 1:2),GetLastError()); } #else if (!ReleaseSemaphore(ghSemaphore,1,NULL) ) { printf("ReleaseSemaphore error in thread %d: error # %d\n",(thread_handle == Handle_Of_Thread_1 ? 1:2), GetLastError()); } #endif return 0; } DWORD WINAPI Thread_no_1( LPVOID lpParam ) { my_critical_section_code(Handle_Of_Thread_1); return 0; } DWORD WINAPI Thread_no_2( LPVOID lpParam ) { my_critical_section_code(Handle_Of_Thread_2); return 0; } 

二进制信号量和互斥量的区别是:

互斥体仅用于相互排斥。 二进制可以使用互斥和同步。 采取互斥的任务只能给互斥。 从ISR不能给出互斥。 recursion的互斥信号是可能的。 这意味着在最终释放一个信号量之前,一个任务可以不止一次地取得信号量。 select使用DELETE_SAFE的任务由Mutex提供,这意味着在持有互斥锁时不能执行任务删除。

二进制信号量和互斥量之间有一个模糊的地方。 我们可能会碰到一个互斥体是二进制信号量。 但他们不是! 互斥和信号量的目的是不同的。 可能是,由于其实现的相似性,互斥体将被称为二进制信号量。

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

信号量是信号机制(“我做完了,你可以进行”这种信号)。 例如,如果您正在手机上收听歌曲(假定为一项任务),同时您的朋友打电话给您,则会触发一个中断,中断服务例程(ISR)将通过该中断向唤醒的呼叫处理任务发出信号。

虽然二进制信号量可以用作互斥量,但互斥量是一个更具体的用例,因为只有locking互斥量的进程才能解锁它。 这种所有权约束可以提供保护,防止:

  • 意外释放
  • recursion死锁
  • 任务死亡僵局

这些限制并不总是存在,因为它们降低了速度。 在开发代码的过程中,您可以暂时启用这些检查。

例如你可以在你的互斥体中启用错误检查属性。 错误检查互斥锁返回EDEADLK如果你试图locking相同的两次EPERM如果你解锁一个不是你自己的互斥锁。

 pthread_mutex_t mutex; pthread_mutexattr_t attr; pthread_mutexattr_init (&attr); pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK_NP); pthread_mutex_init (&mutex, &attr); 

一旦初始化,我们可以将这些检查放在我们的代码中,像这样:

 if(pthread_mutex_unlock(&mutex)==EPERM) printf("Unlock failed:Mutex not owned by this thread\n"); 

互斥量用于保护敏感的代码和数据,信号量用于同步。您也可以实际使用保护敏感代码,但是可能存在通过操作V释放其他线程的保护的风险。双倍信号量和互斥量之间的区别就是所有权。例如通过厕所,互斥量就好像人们可以进入厕所并锁上门一样,除非人出来,否则其他人都不能进入,双倍信号就好像可以进入上厕所锁门,但别人可以通过要求pipe理员开门,这是可笑的。

互斥体:假设我们有临界区段线程T1想要访问它然后按照下面的步骤。 T1:

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

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

  1. 等待(s)/ /最初s值是零后,等待它的值增加1即1
  2. 使用关键部分
  3. 信号(s)//现在s值减小并且变为0

互斥锁和二进制信号量的主要区别是在Mutext调用线程中locking临界区,那么它必须解锁临界区,其他线程才能解锁它,但是在二进制信号的情况下,如果一个线程使用wait(s)函数locking临界区, of s become "0" and no one can access it until value of "s" become 1 but suppose some other thread calls signal(s) then value of "s" become 1 and it allows other function to use critical section. hence in Binary semaphore thread doesn't have ownership.

The answer may depend on the target OS. For example, at least one RTOS implementation I'm familiar with will allow multiple sequential "get" operations against a single OS mutex, so long as they're all from within the same thread context. The multiple gets must be replaced by an equal number of puts before another thread will be allowed to get the mutex. This differs from binary semaphores, for which only a single get is allowed at a time, regardless of thread contexts.

The idea behind this type of mutex is that you protect an object by only allowing a single context to modify the data at a time. Even if the thread gets the mutex and then calls a function that further modifies the object (and gets/puts the protector mutex around its own operations), the operations should still be safe because they're all happening under a single thread.

 { mutexGet(); // Other threads can no longer get the mutex. // Make changes to the protected object. // ... objectModify(); // Also gets/puts the mutex. Only allowed from this thread context. // Make more changes to the protected object. // ... mutexPut(); // Finally allows other threads to get the mutex. } 

Of course, when using this feature, you must be certain that all accesses within a single thread really are safe!

I'm not sure how common this approach is, or whether it applies outside of the systems with which I'm familiar. For an example of this kind of mutex, see the ThreadX RTOS.

Mutexes have ownership, unlike semaphores. Although any thread, within the scope of a mutex, can get an unlocked mutex and lock access to the same critical section of code, only the thread that locked a mutex should unlock it .

A mutex is essentially the same thing as a binary semaphore and sometimes uses the same basic implementation. The differences between them are in how they are used. While a binary semaphore may be used as a mutex, a mutex is a more specific use-case, which allows extra guarantees:

  1. Mutexes have a concept of an owner. Only the process that locked the mutex is supposed to unlock it. If the owner is stored by the mutex this can be verified at runtime.
  2. Mutexes may provide priority inversion safety. If the mutex knows its current owner, it is possible to promote the priority of the owner whenever a higher-priority task starts waiting on the mutex.
  3. Mutexes may also provide deletion safety, where the process holding the mutex cannot be accidentally deleted.

Mutex & Binary semaphore is both of same usage but in reality, They are different. In Case of mutex, The Thread which have Locked it, Only that can unlock it. If any other thread comes to lock it, It will wait. But in Case of semaphone, Its not the case. Semaphore is not tied up with a partucular thread ID.