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

时间:2008-09-15 13:23:06

标签: operating-system mutex semaphore glossary

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

37 个答案:

答案 0 :(得分:639)

他们同样的事情。它们用于不同的目的!
虽然两种类型的信号量都具有完整/空状态并使用相同的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

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

答案 1 :(得分:418)

The Toilet example是一个令人愉快的比喻:

  

互斥:

     

是厕所的钥匙。一个人可以   有钥匙 - 占用厕所 - 在   时间。完成后,该人   给下一个(释放)密钥   在队列中的人。

     

官方说:“互斥体通常是   用于序列化对部分的访问   无法重入的代码   由多个人同时执行   线。互斥对象只允许一个   线程进入受控部分,   强制尝试其他线程   获得访问该部分等待   直到第一个线程退出   那部分。“参考:Symbian开发者   文库

     

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

     

信号量:

     

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

     

正式:“信号量限制了   a的同时用户数   共享资源最多   数。线程可以请求访问   资源(递减)   信号量),并且可以发出信号   已经完成使用资源   (增加信号量)。“参考:   Symbian开发人员库

答案 2 :(得分:413)

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

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

答案 3 :(得分:140)

关于这个主题的好文章:

从第2部分开始:

  

互斥体类似于原则   二进制信号量与一个   显着差异:原则   所有权。所有权很简单   任务锁定时的概念   (获取)只有它可以解锁的互斥锁   (释放)它。如果任务试图   解锁一个没有锁定的互斥锁(因此   不拥有)然后是错误条件   遇到了,最重要的是,   互斥锁未解锁。如果   互斥对象没有   所有权然后,与它无关   被称为,它不是互斥体。

答案 4 :(得分:93)

由于上述答案都没有解决这一混淆,因此可以解决这个问题。

  

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

     

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

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

答案 5 :(得分:37)

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

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

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

答案 6 :(得分:35)

  • 根据定义, Mutex 用于序列化对一部分无法同时执行的可重入代码的访问 不止一个主题。

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

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

  • 信号量和Mutex(至少是最新的内核)本质上都是非递归的。
  • 没有人拥有信号量,而Mutex是拥有的,所有者对其负责。这很重要 区别于调试的角度。
  • 如果是Mutex,拥有Mutex的线程负责释放它。但是,在信号量的情况下,这个 条件不是必需的。任何其他线程都可以通过使用s m p s(function.e_ot)发出信号以释放信号量

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

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

答案 7 :(得分:21)

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

实际差异(就其周围的系统服务而言)是互斥体的实现旨在成为更轻量级的同步机制。在oracle-speak中,互斥锁称为latches,信号量称为waits

在最低级别,他们使用某种原子test and set机制。这将读取内存位置的当前值,计算某种条件,并在cannot be interrupted的单个指令中在该位置写出一个值。这意味着您可以获取互斥锁并进行测试以确定是否有其他人在您之前拥有它。

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

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.

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

信号量是一种同步数据结构(通常使用互斥锁),它具有一个计数和一些系统调用包装器,它们与调度器交互的程度比互斥库更深。信号量递增和递减并用于block任务,直到其他东西准备好。有关此问题的简单示例,请参阅Producer/Consumer Problem。信号量初始化为某个值 - 二进制信号量只是信号量初始化为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.

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

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

答案 8 :(得分:18)

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

答案 9 :(得分:11)

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

  1. 锁定
  2. 使用关键部分
  3. 解锁
  4. 二进制信号量:它基于信令等待和信号工作。 等待减少&#34; s&#34;价值通常是一个&#34; s&#34;值初始化为值&#34; 1&#34;, 信号增加&#34; s&#34;价值一个。如果&#34; s&#34;值为1表示没有人使用临界区,当值为0表示临界区正在使用中。 假设线程T2正在使用临界区,那么它遵循以下步骤。 T2:

    1. 等待//最初s值是一个在调用之后等待它的值减少了一个即0
    2. 使用关键部分
    3. signal(s)//现在s值增加,变为1
    4. Mutex和Binary信号量之间的主要区别在于Mutext如果线程锁定临界区然后它必须解锁临界区而没有其他线程可以解锁它,但是在Binary信号量的情况下如果一个线程使用wait(s)锁定临界区函数然后s的值变为&#34; 0&#34;没有人可以访问它,直到&#34; s&#34;成为1,但假设某些其他线程调用信号,那么&#34; s&#34;成为1,它允许其他功能使用临界区。 因此在Binary信号量线程中没有所有权。

答案 10 :(得分:10)

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

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

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

答案 11 :(得分:10)

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

,而

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

答案 12 :(得分:10)

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

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

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

答案 13 :(得分:9)

神话:

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

要点:

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

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

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

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

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

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

答案 14 :(得分:8)

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

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

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

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

答案 15 :(得分:6)

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

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

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

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

答案 16 :(得分:6)

Mutex致力于阻止关键区域,但Semaphore正在计算。

答案 17 :(得分:5)

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

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

如果他/她想使用二进制信号量代替互斥量,那么可以由程序员使用。

答案 18 :(得分:5)

Binary Semaphore和Mutex之间的差异: 所有权: 信号量甚至可以从非当前所有者发出信号(发布)。这意味着您可以从任何其他主题发帖,但您不是所有者。

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

答案 19 :(得分:4)

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

答案 20 :(得分:4)

在Windows中,差异如下。 成功执行等待 MUTEX:过程必须执行信号,反之亦然。 BINARY SEMAPHORES:不同的流程可以对信号量执行等待信号操作。

答案 21 :(得分:4)

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

当我们试图给出信号量而不接受信号量时,它会通过。但是,当你尝试不使用互斥锁时,它会失败。我在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_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;
}

答案 22 :(得分:3)

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

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

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

e.g。您可以在互斥锁中启用错误检查属性。如果您尝试锁定相同的互斥锁,则检查互斥锁的错误会返回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");

答案 23 :(得分:2)

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

答案 24 :(得分:2)

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

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

答案 25 :(得分:1)

答案可能取决于目标操作系统。例如,我熟悉的至少一个RTOS实现将允许针对单个OS互斥锁进行多个顺序“获取”操作,只要它们都来自同一个线程上下文。在允许另一个线程获取互斥锁之前,必须用相同数量的put替换多个gets。 这与二进制信号量不同,无论线程上下文如何,一次只允许一次获取。

这种互斥体背后的想法是,通过仅允许单个上下文一次修改数据来保护对象。即使线程获得互斥锁然后调用一个进一步修改对象的函数(并将保护器互斥体置于其自己的操作中),操作仍然应该是安全的,因为它们都发生在单个线程下。

{
    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。

答案 26 :(得分:1)

正如这里的许多人提到的,互斥锁用于保护关键代码段(AKA关键部分)。您将获得互斥锁(锁定),输入临界区,并释放互斥锁(解锁)全部在同一个帖子中

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

答案 27 :(得分:1)

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

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

对于semaphone,情况并非如此。信号量与特定的线程ID无关。

答案 28 :(得分:1)

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

答案 29 :(得分:0)

“二进制信号量”是一种使用诸如“ mutex”之类的“信号量”的编程语言。显然有两个很大的不同:

  1. 每个人的呼叫方式。

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

答案 30 :(得分:0)

Mutex

Mutexe通常用于序列化对不能由多个线程同时执行的可重入代码段的访问。互斥对象仅允许一个线程进入受控部分,从而迫使试图访问该部分的其他线程要等到第一个线程退出该部分后再使用。正确使用互斥对象是为了保护共享资源,可能会有危险。意外的副作用。在不同优先级下运行并通过互斥体进行协调的任何两个RTOS任务都会为 优先级倒置 创造机会。 Mutex在 用户空间 中工作。

信号量

信号量是一种信号传导机制。信号量将共享资源的同时用户数限制为最大数量。线程可以请求对资源的访问(减少信号量),并且可以发出信号,表明它们已经完成了对资源的使用(增加信号量)。它允许线程数访问共享资源。信号量的正确用法是用于将信号从一个任务发送到另一任务。信号量还可以用于从 中断服务例程 发出信号。 >(ISR)执行任务。发信号量信号是一种无阻塞的RTOS行为,因此具有ISR安全性。因为此技术消除了在任务级别禁用中断的易于出错的需求,所以可以在 内核空间 中使用。

答案 31 :(得分:0)

基本问题是并发性。有不止一个控制流。考虑使用共享内存的两个进程。现在,一次只有一个进程可以访问共享内存。如果一次有多个进程访问共享内存,则共享内存的内容将被破坏。就像铁轨一样。只有一列火车可以在其上行驶,否则会发生事故,因此存在一种信号机制,驾驶员可以进行检查。如果信号为绿色,则火车可以行驶;如果信号为红色,则必须等待使用轨道。类似地,在共享内存的情况下,有一个二进制信号量。如果信号量为1,则进程将其获取(将其设置为0)并继续进行访问。如果信号量为0,则过程等待。二进制信号量必须提供的功能是互斥(简称互斥),因此许多并发实体(进程或线程)中只有一个相互排斥其他实体。我们拥有计数信号量的优点,这有助于同步资源的多个实例。

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

答案 32 :(得分:0)

最佳解决方案

唯一的区别是

1.Mutex->锁定和解锁处于锁定互斥锁的线程的所有权之下。

2。信号量->没有所有权,即;如果一个线程调用semwait,则任何其他线程都可以调用sempost来删除锁。

答案 33 :(得分:0)

MUTEX

直到最近,内核中唯一的睡眠锁是信号灯。大多数使用信号量的用户都实例化了一个计数为1的信号量,并将其视为互斥锁(自旋锁的休眠版本)。不幸的是,信号量是相当通用的,没有施加任何使用限制。这使它们对于在晦涩的情况下(例如内核和用户空间之间的复杂舞蹈)管理独占访问很有用。但这也意味着更难进行锁定,而且缺少强制性规则使得不可能进行任何类型的自动调试或约束性强制执行。为了寻求更简单的睡眠锁,内核开发人员引入了互斥锁。是的,正如您现在所习惯的,这是一个令人困惑的名称。让我们澄清一下。术语“互斥体”是一个通用名称,指的是强制执行互斥的任何睡眠锁,例如使用计数为1的信号灯。在最近的Linux内核中,专有名词“互斥锁”现在也是实现互斥的特定类型的睡眠锁。也就是说,互斥锁是互斥锁。

互斥量的简单性和效率来自于它给用户带来的超出信号量所需的其他限制。与根据Dijkstra的原始设计实现最基本行为的信号量不同,互斥量具有更严格,更狭窄的用例: n一次只有一个任务可以保存互斥量。也就是说,互斥量的使用次数始终为1。

  1. 锁定互斥锁的人必须将其解锁。也就是说,您不能将一个互斥锁锁定在一个 上下文,然后将其解锁。这意味着互斥锁不适用于内核和用户空间之间更复杂的同步。大多数用例 但是,请从相同的上下文中干净地锁定和解锁。
  2. 不允许递归锁定和解锁。也就是说,您不能递归获取相同的互斥锁,也无法解锁未锁定的互斥锁。
  3. 持有互斥锁时进程无法退出。
  4. 即使遇到以下情况,中断处理程序或下半部分也无法获取互斥锁: Mutex_trylock()。
  5. 互斥锁只能通过官方API进行管理:必须通过本节中介绍的方法对其进行初始化,并且不能对其进行复制,手动初始化或重新初始化。

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

答案 34 :(得分:0)

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

答案 35 :(得分:-2)

几乎所有上述说得对。如果有人仍有疑问,我还要试着澄清一下。 互斥 - &gt;用于序列化 Semaphore-&GT;同步。 然而,两者的目的不同,通过仔细编程可以通过它们实现相同的功能。 标准实施例 - &gt;生产者消费问题。 SemaVar的初始值= 0

生产者消费者 --- SemaWait() - &gt;减少SemaVar

生成数据

SemaSignal SemaVar或SemaVar ++ ---&gt;消费者解锁,因为SemVar现在为1。

希望我能澄清一下。

答案 36 :(得分:-2)

您可以通过以下方式清楚地记住区别:

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

  2. 信号量:用于表示资源的可用性。 信号量既可以跨进程使用,也可以跨进程使用。