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


当前回答

虽然二进制信号量可以用作互斥量,但互斥量是一个更具体的用例,因为只有锁定了互斥量的进程才应该解锁它。这种所有权限制使我们有可能对以下情况提供保护:

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

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

例如,你可以在互斥锁中启用错误检查属性。错误检查互斥量返回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 is used to protect the sensitive code and data, semaphore is used to synchronization.You also can have practical use with protect the sensitive code, but there might be a risk that release the protection by the other thread by operation V.So The main difference between bi-semaphore and mutex is the ownership.For instance by toilet , Mutex is like that one can enter the toilet and lock the door, no one else can enter until the man get out, bi-semaphore is like that one can enter the toilet and lock the door, but someone else could enter by asking the administrator to open the door, it's ridiculous.

互斥锁

Until recently, the only sleeping lock in the kernel was the semaphore. Most users of semaphores instantiated a semaphore with a count of one and treated them as a mutual exclusion lock—a sleeping version of the spin-lock. Unfortunately, semaphores are rather generic and do not impose any usage constraints. This makes them useful for managing exclusive access in obscure situations, such as complicated dances between the kernel and userspace. But it also means that simpler locking is harder to do, and the lack of enforced rules makes any sort of automated debugging or constraint enforcement impossible. Seeking a simpler sleeping lock, the kernel developers introduced the mutex.Yes, as you are now accustomed to, that is a confusing name. Let’s clarify.The term “mutex” is a generic name to refer to any sleeping lock that enforces mutual exclusion, such as a semaphore with a usage count of one. In recent Linux kernels, the proper noun “mutex” is now also a specific type of sleeping lock that implements mutual exclusion.That is, a mutex is a mutex.

互斥锁的简单性和效率来自于它在信号量要求之外强加给用户的附加约束。信号量是按照Dijkstra的原始设计来实现最基本的行为,而互斥锁则不同,它的用例更严格、更窄: n一次只能有一个任务持有互斥锁。也就是说,互斥锁的使用计数总是1。

Whoever locked a mutex must unlock it. That is, you cannot lock a mutex in one context and then unlock it in another. This means that the mutex isn’t suitable for more complicated synchronizations between kernel and user-space. Most use cases, however, cleanly lock and unlock from the same context. Recursive locks and unlocks are not allowed. That is, you cannot recursively acquire the same mutex, and you cannot unlock an unlocked mutex. A process cannot exit while holding a mutex. A mutex cannot be acquired by an interrupt handler or bottom half, even with mutex_trylock(). A mutex can be managed only via the official API: It must be initialized via the methods described in this section and cannot be copied, hand initialized, or reinitialized.

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

互斥锁只能由获得它的线程释放。 二进制信号量可以由任何线程(或进程)发出信号。

因此,信号量更适合于一些同步问题,如生产者-消费者。

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

以上几乎所有人都说对了。如果有人还有疑问,让我来澄清一下。

互斥->用于序列化 信号- >同步。

两者的目的是不同的,但是,通过精心的编程,可以实现相同的功能。

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

initial value of SemaVar=0

Producer                           Consumer
---                                SemaWait()->decrement SemaVar   
produce data
---
SemaSignal SemaVar or SemaVar++  --->consumer unblocks as SemVar is 1 now.

希望我能澄清。

答案可能取决于目标操作系统。例如,我所熟悉的至少一个RTOS实现允许对单个OS互斥量进行多个连续的“get”操作,只要它们都来自同一个线程上下文中。在允许另一个线程获得互斥量之前,多个get必须被相等数量的put替换。这与二进制信号量不同,对于二进制信号量,无论线程上下文如何,一次只允许一个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。