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

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

646982 次浏览
  • 互斥锁只能由获得它的线程释放。
  • 二元信号量可以用信号通知由任何线程(或进程)。

所以信号量更适合一些同步问题,比如生产者-消费者。

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

答案可能取决于目标操作系统。例如,至少有一个我熟悉的RTOS实现将允许对单个操作系统的多个顺序“get”操作互斥锁,只要它们都来自同一个线程上下文。在允许另一个线程获得互斥锁之前,多个get必须被等量的放置替换。这与二进制信号量不同,二进制信号量一次只允许一个get,而不管线程上下文如何。

这种类型的互斥锁背后的思想是通过一次只允许单个上下文修改数据来保护对象。即使线程获得互斥锁,然后调用进一步修改对象的函数(并在自己的操作周围获得/放置保护者互斥锁),操作仍然应该是安全的,因为它们都发生在单个线程下。

{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.}

当然,在使用此功能时,您必须确保单个线程中的所有访问都是安全的!

我不确定这种方法有多普遍,或者它是否适用于我熟悉的系统之外。有关这种互斥锁的示例,请参阅ThreadX RTOS。

它们是相同的东西。它们用于不同的目的!
虽然两种类型的信号量都具有满/空状态并使用相同的API,但它们的用法非常不同。

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

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

互斥体始终使用以下序列:

- SemTake- Critical Section- SemGive

这里有一个简单的例子:

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

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

  • 任务B等待某些事情发生(例如传感器被绊倒)。
  • 传感器跳闸和中断服务例程运行。它需要通知跳闸的任务。
  • 任务B应该运行并对传感器跳闸采取适当的操作。然后返回等待。
Task A                      Task B...                         Take BinSemaphore   <== wait for somethingDo Something NoteworthyGive BinSemaphore           do something    <== unblocks

请注意,对于二进制信号量,B接受信号量而A给出信号量是可以的。
同样,二进制信号量并没有保护资源免受访问。给予和获取信号量的行为从根本上是解耦的。
对于相同的任务,对相同的二进制信号量进行给予和接受通常没有什么意义。

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

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

因此,可以将互斥锁视为从任务传递到任务的令牌,将信号量视为交通红灯(它信号可以继续)。

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

  1. 互斥锁只能由拥有所有权的线程释放,即以前调用过等待函数的线程(或在创建它时拥有所有权的线程)。信号量可以由任何线程释放。

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

Mutex工作在阻塞关键区域,但Semaphore工作在计数上。

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

实际的区别(就它们周围的系统服务而言)是互斥锁的实现旨在成为一种更轻量级的同步机制。在甲骨文中,互斥锁被称为闩锁,信号量被称为等待

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

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

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

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

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

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

(somewhere in the program startup)Initialise the semaphore to its start-up value.
Acquiring a semaphorei. (synchronised) Attempt to decrement the semaphore valueii. 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 semaphorei. (synchronised) Increment the semaphore valueii. 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.

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

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

厕所的例子是一个有趣的类比:

互斥锁:

是厕所的钥匙。一个人可以有钥匙-占用厕所-在时间。完成后,人给(释放)钥匙到下一个#36825;人排队

官方:“互斥通常是用于序列化对节的访问不能重入的代码由不止一个人同时执行一个互斥锁对象只允许一个穿入受控部分,强迫其他试图访问该部分以等待直到第一个线程退出该部分。”参考:Symbian Developer图书馆

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

信号量:

免费厕所的数量是否相同钥匙。例如,我们有四个厕所有相同的锁和钥匙。信号量计数-的计数键-开始时设置为4(全部四个厕所是免费的),然后计数价值随着人的减少而减少进来。如果所有厕所都满了,也就是说,没有免费的钥匙了信号量计数为0。现在,当eq。一个人离开厕所,信号量增加到1(一个免费键),并给予下一个人队列。

正式:“信号量限制了a的同时用户数最大限度地共享资源数量。线程可以请求访问资源(递减信号量),并可以表明他们资源使用完毕(增加信号量)。”参考:Symbian开发者库

不错的文章主题:

第二部分:

互斥锁的原理类似于二进制信号量的一主要区别:原则所有权。所有权很简单概念当任务锁定时(获得)互斥锁只有它能解锁(释放)它。如果一个任务试图解锁一个互斥锁它没有锁定(因此不拥有)然后是错误条件遇到了,最重要的是,互斥锁未解锁。如果互斥对象没有那么所有权,与它无关是调用,它不是一个互斥锁。

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

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

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

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

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

互斥锁控制对单个共享资源的访问。它为获取访问该资源和发行版访问该资源提供操作。

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

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

因此,信号量是比Mutex更高级别的抽象。Mutex可以使用信号量实现,但不能反过来。

在Windows中,差异如下。MUTEX:成功执行等待的进程必须执行信号,反之亦然。二元半身:不同的进程可以对信号量执行等待信号操作。

与信号量不同,互斥锁具有所有权。尽管在互斥锁范围内的任何线程都可以获得未锁定的互斥锁并锁定对相同关键代码段的访问,只有锁定互斥锁的线程才能解锁它

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

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

这取决于程序员是否想使用二进制信号量来代替互斥锁。

显然,你使用互斥锁来锁定一个线程中的数据,同时被另一个线程访问。假设你刚刚调用了lock()并且正在访问数据。这意味着你不期望任何其他线程(或相同线程代码的另一个实例)访问由相同互斥锁锁定的相同数据。也就是说,如果它是在不同线程实例上执行的相同线程代码,命中锁,那么lock()应该阻止那里的控制流。这适用于使用不同线程代码的线程,它也访问相同的数据,并且也被相同的互斥锁锁定。在这种情况下,你仍在访问数据的过程中,你可能需要,比如说,另外15秒才能到达互斥锁解锁(这样在互斥锁中被阻塞的另一个线程将解除屏蔽并允许控件访问数据)。你是否不惜一切代价允许另一个线程刚刚解锁同一个互斥锁,反过来,允许已经在互斥锁中等待(阻塞)的线程解除屏蔽并访问数据?希望你明白我在这里说的?#36825;的统一定义!

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

所以,如果你对使用二进制信号量而不是互斥锁非常挑剔,那么你应该非常小心地“限定”锁和解锁。我的意思是每个命中每个锁的控制流都应该命中一个解锁调用,也不应该有任何“第一次解锁”,而应该总是“第一次锁定”。

互斥锁用于保护敏感代码和数据,信号量用于同步。您也可以实际使用保护敏感代码,但是可能存在通过操作V释放另一个线程的保护的风险。所以双信号量和互斥锁的主要区别是所有权。例如,对于厕所,互斥锁就像一个人可以进入厕所并锁门,其他人不能进入,直到男人出去,双信号量就像一个人可以进入厕所并锁门,但是其他人可以通过要求管理员开门来进入,这太荒谬了。

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

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

在看了上面的帖子后,这个概念对我来说很清楚。但是有一些挥之不去的问题。所以,我写了这段小代码。

当我们试图给出一个信号量而不接受它时,它会通过。但是,当你试图给出一个互斥锁而不接受它时,它会失败。我在Windows平台上测试了这个。使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_MUTEXghMutex = 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_COUNTghSemaphore = 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 secondsSleep(20 * 1000);
printf("Out of the program \n");return 0;}

int my_critical_section_code(HANDLE thread_handle){
#ifdef USE_MUTEXif(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_MUTEXprintf("Thread 1 about to release mutex \n");#elseprintf("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());}#elseif (!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)将向呼叫处理任务发出唤醒信号。

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

神话:

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

核心进展:

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

一个互斥锁可以被锁定不止一次,只有当它是一个递归互斥锁,这里锁和解锁互斥锁应该是相同的

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

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

由于与Mutex相关的保护协议,Mutex的运行成本很高。

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

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

二进制信号量和互斥量之间的差异:所有权:信号量甚至可以从非当前所有者发出信号(发布)。这意味着您可以简单地从任何其他线程发布,尽管您不是所有者。

Semaphore是进程中的公共属性,它可以由非所有者线程简单地发布。请用粗体字母标记这个差异,这意味着很多。

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

在互斥锁的情况下,只有锁定它的线程才能解锁它。如果任何其他线程来锁定它,它将等待。

在信号音的情况下,情况并非如此。信号音与特定的线程ID无关。

以上几乎所有人都说得对。让我也试着澄清一下是否有人仍然有疑问。

  • Mutex->用于序列化
  • 信号量->同步。

两者的目的是不同的,但是,通过仔细的编程,可以通过它们实现相同的功能。

标准示例->生产者消费者问题。

initial value of SemaVar=0
Producer                           Consumer---                                SemaWait()->decrement SemaVarproduce data---SemaSignal SemaVar or SemaVar++  --->consumer unblocks as SemVar is 1 now.

希望我能澄清。

正如这里的许多人提到的,互斥锁用于保护关键代码段(又名临界区)。您将获得互斥锁(lock),进入临界区,然后释放互斥锁(解锁)都在同一条线上

在使用信号量时,您可以让一个线程等待信号量(例如线程A),直到另一个线程(例如线程B)完成任何任务,然后为线程A设置信号量以停止等待,并继续其任务。

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

  • 意外释放
  • 递归死锁
  • 任务死锁

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

例如,您可以在互斥锁中启用错误检查属性。如果您尝试两次锁定相同的互斥锁,错误检查互斥锁将返回EDEADLK,如果您解锁不是您的互斥锁,则返回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");

Mutex:假设我们有临界区线程T1想要访问它,那么它遵循以下步骤。T1:

  1. 锁定
  2. 使用临界区
  3. 解锁

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

  1. 等待(s)//最初s的值是1,调用等待后它的值减少了1,即0
  2. 使用临界区
  3. 信号(s)//现在的值增加并变为1

互斥锁和二进制信号量之间的主要区别是在Mutext-如果线程锁定临界区,那么它必须解锁临界区,没有其他线程可以解锁它,但是在二进制信号量的情况下,如果一个线程使用等待(s)函数锁定临界区,那么s的值变成“0”,没有人可以访问它,直到“s”的值变成1,但假设其他线程调用信号,那么“s”的值变成1,它允许其他函数使用临界区。因此在二进制信号量线程没有所有权。

“二进制信号量”是一种规避使用“信号量”(如“互斥锁”)的编程语言。显然有两个非常大的区别:

  1. 你称呼他们每个人的方式。

  2. “标识符”的最大长度。

基本问题是并发。控制流程不止一个。想象两个进程使用共享内存。现在一次只有一个进程可以访问共享内存。如果一个以上的进程同时访问共享内存,共享内存的内容就会损坏。这就像铁轨。只有一列火车可以在上面运行,否则就会发生事故。所以有一个信号机制,司机检查。如果信号是绿色的,火车可以走,如果是红色的,它必须等待使用轨道。类似地,在共享内存的情况下,有一个二进制信号量。如果信号量为1,则进程获取它(使其为0)并继续访问它。如果信号量为0,则进程等待。二进制信号量必须提供的功能是互斥(或互斥锁,简而言之),以便许多并发实体(进程或线程)中只有一个相互排斥其他实体。我们有计数信号量是一个优点,这有助于同步资源的多个实例。

互斥是信号量提供的基本功能。现在在线程的上下文中,我们可能对它有不同的名称和语法。但基本概念是一样的:如何在并发编程中保持代码和数据的完整性。在我看来,所有权和相关检查等东西是实现提供的改进。

最佳解决方案

唯一的区别是

1.互斥锁->锁和解锁属于锁定互斥锁的线程。

2. Semaphore->没有所有权,即;如果一个线程调用semetc(s),任何其他线程都可以调用sempost(s)来删除锁。

MUTEX

直到最近,内核中唯一的睡眠锁是信号量。信号量的大多数用户实例化了一个计数为1的信号量,并将它们视为互斥锁——自旋锁的休眠版本。不幸的是,信号量相当通用,不强加任何使用约束。这使得它们在模糊的情况下管理独占访问很有用,例如内核和用户空间之间复杂的舞蹈。但这也意味着更简单的锁定更难做到,并且缺乏强制规则使得任何形式的自动调试或约束执行都不可能。为了寻找一个更简单的睡眠锁,内核开发人员引入了Mutex。让我们澄清一下。术语"互斥锁"是一个通用名称,指任何强制互斥的睡眠锁,例如使用次数为1的信号量。在最近的Linux内核中,专有名词"互斥锁"现在也是实现互斥的特定类型的睡眠锁。也就是说,互斥锁就是互斥锁。

互斥锁的简单性和效率来自于它对用户施加的额外约束,超出了信号量的要求。与按照Dijkstra原始设计实现最基本行为的信号量不同,互斥锁有更严格、更窄的用例:一次只有一个任务可以持有互斥锁。也就是说,互斥锁的使用计数总是一个。

  1. 锁互斥锁的人必须解锁它。也就是说,你不能把互斥锁锁在一个上下文,然后在另一个上下文中解锁。这意味着互斥锁不适合内核和用户空间之间更复杂的同步。但是,从相同的上下文中干净地锁定和解锁。
  2. 不允许递归锁和解锁。也就是说,您不能递归获取相同的互斥锁,也不能解锁未锁定的互斥锁。
  3. 持有互斥锁的进程不能退出。
  4. 中断处理程序或下半部不能获取互斥锁,即使使用mutex_trylock
  5. 互斥锁只能通过官方API进行管理:它必须通过本节中描述的方法进行初始化,并且不能复制、手动初始化或重新初始化。

[1]Linux内核开发,第三版Robert Love

我认为这里的大多数答案都令人困惑,尤其是那些说互斥锁只能由持有它的进程释放,但信号量可以由ay进程发出信号的答案。就信号量而言,上面的行有点模糊。要理解我们应该知道有两种信号量,一种称为计数信号量,另一种称为二进制信号量。在计数信号量中,处理对n个资源的访问,其中n可以在使用前定义。每个信号量都有一个计数变量,它保持使用中资源数量的计数,最初,它被设置为n。每个希望使用资源的进程对信号量执行等待()操作(从而减少计数)。当一个进程释放资源时,它会执行释放()操作(增加计数)。当计数变为0时,所有资源都在使用中。之后,该进程等待直到计数超过0。现在这里是捕获只有持有资源的进程可以增加计数没有其他进程可以增加计数只有持有资源的进程可以增加计数,并且再次等待信号量的进程检查,当它看到可用资源时,它再次减少计数。因此,就二进制信号量而言,只有持有信号量的进程才能增加计数,并且计数保持为零,直到它停止使用信号量并增加计数并且其他进程有机会访问信号量。

二进制信号量和互斥锁之间的主要区别在于信号量是一种信号机制,互斥锁是一种锁定机制,但是二进制信号量似乎像互斥锁一样产生混淆,但两者都是不同的概念,适用于不同类型的工作。

你可以清楚地记得这个区别:

  1. 互斥锁:用于保护关键区域,Mutex不能跨进程使用,只能在单进程中使用

  2. Semaphore:用于通知资源的可用性。信号量可以跨进程和跨进程使用。

互斥量是任何打算解决临界段问题的算法都必须遵循的标准(4个),而二进制信号量本身是一个可以取值0和1的变量。

  • Mutex使用锁定机制,即如果一个进程想要使用然后它锁定资源,使用它,然后释放它。但是另一方面,信号量使用一种信令机制,其中等待()和信号()方法用于显示进程是否正在释放资源或获取资源。
  • 互斥锁是一个对象,但信号量是一个整数变量。
  • 在信号量中,我们有等待()和信号()函数。但是在互斥锁中,没有这样的函数。
  • 互斥锁对象允许多个进程线程访问单个共享资源,但一次只能使用一个。另一方面,信号量允许多个进程线程访问直到资源可用。
  • 在互斥锁中,锁可以由同一个进程获取和释放一次。但是信号量变量的值可以通过任何需要一些资源但只有一个进程可以更改的进程一次的值。

有用的阅读,我从这里学习和复制