Open In App

Mutex vs Semaphore

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

In the Operating System, Mutexes and Semaphores are kernel resources that provide synchronization services (also known as synchronization primitives). Synchronization is required when multiple processes are executing concurrently, to avoid conflicts between processes using shared resources.

Mutex

Mutex is a specific kind of binary semaphore that is used to provide a locking mechanism. It stands for Mutual Exclusion Object. Mutex is mainly used to provide mutual exclusion to a specific portion of the code so that the process can execute and work with a particular section of the code at a particular time. 

Mutex uses a priority inheritance mechanism to avoid priority inversion issues. The priority inheritance mechanism keeps higher-priority processes in the blocked state for the minimum possible time. However, this cannot avoid the priority inversion problem, but it can reduce its effect up to an extent. 

Advantages of Mutex

  • No race condition arises, as only one process is in the critical section at a time.
  • Data remains consistent and it helps in maintaining integrity.
  • It’s a simple locking mechanism that can be obtained by a process before entering into a critical section and released while leaving the critical section.

Disadvantages of Mutex

  • If after entering into the critical section, the thread sleeps or gets preempted by a high-priority process, no other thread can enter into the critical section. This can lead to starvation.
  • When the previous thread leaves the critical section, then only other processes can enter into it, there is no other mechanism to lock or unlock the critical section.
  • Implementation of mutex can lead to busy waiting that leads to the wastage of the CPU cycle.

Using Mutex

The producer-consumer problem: Consider the standard producer-consumer problem. Assume, we have a buffer of 4096-byte length. A producer thread collects the data and writes it to the buffer. A consumer thread processes the collected data from the buffer. The objective is, both the threads should not run at the same time. 

Solution- A mutex provides mutual exclusion, either producer or consumer can have the key (mutex) and proceed with their work. As long as the buffer is filled by the producer, the consumer needs to wait, and vice versa. At any point in time, only one thread can work with the entire buffer. The concept can be generalized using semaphore. 

Note- The content is a generalized explanation. Practical details vary with implementation. 

Semaphore

A semaphore is a non-negative integer variable that is shared between various threads. Semaphore works upon signaling mechanism, in this a thread can be signaled by another thread. Semaphore uses two atomic operations for process synchronisation: 

  • Wait (P)
  • Signal (V)

Advantages of Semaphore

  • Multiple threads can access the critical section at the same time.
  • Semaphores are machine-independent.
  • Only one process will access the critical section at a time, however, multiple threads are allowed.
  • Semaphores are machine-independent, so they should be run over microkernel.
  • Flexible resource management.

Disadvantages of Semaphore

  • It has priority inversion.
  • Semaphore’s operation (Wait, Signal) must be implemented in the correct manner to avoid deadlock.
  • It leads to a loss of modularity, so semaphores can’t be used for large-scale systems.
  • Semaphore is prone to programming error and this can lead to deadlock or violation of mutual exclusion property.
  • Operating System has to track all the calls to wait and signal operations.

Using Semaphore

The producer-consumer problem: Consider the standard producer-consumer problem. Assume, we have a buffer of 4096-byte length. A producer thread collects the data and writes it to the buffer. A consumer thread processes the collected data from the buffer. The objective is, both the threads should not run at the same time. 

Solution- A semaphore is a generalized mutex. In lieu of a single buffer, we can split the 4 KB buffer into four 1 KB buffers (identical resources). A semaphore can be associated with these four buffers. The consumer and producer can work on different buffers at the same time. 

Note: The content is a generalized explanation. Practical details vary with implementation. 

Difference Between Mutex and Semaphore

Mutex Semaphore
A mutex is an object. A semaphore is an integer.
Mutex works upon the locking mechanism. Semaphore uses signaling mechanism

Operations on mutex:

  • Lock
  • Unlock

Operation on semaphore:

  • Wait
  • Signal
Mutex doesn’t have any subtypes.

Semaphore is of two types:

  • Counting Semaphore
  • Binary Semaphore
A mutex can only be modified by the process that is requesting or releasing a resource. Semaphore work with two atomic operations (Wait, signal) which can modify it.
If the mutex is locked then the process needs to wait in the process queue, and mutex can only be accessed once the lock is released. If the process needs a resource, and no resource is free. So, the process needs to perform a wait operation until the semaphore value is greater than zero. 

Misconception

There is an ambiguity between binary semaphore and mutex. We might have come across that a mutex is a binary semaphore. But it is not! The purposes of mutex and semaphore are different. Maybe, due to similarity in their implementation a mutex would be referred to as a binary semaphore. 

A mutex is a locking mechanism used to synchronize access to a resource. Only one task (can be a thread or process based on OS abstraction) can acquire the mutex. It means there is ownership associated with a mutex, and only the owner can release the lock (mutex). 

Semaphore is a signaling mechanism (“I am done, you can carry on” kind of signal). For example, if you are listening to songs (assume it as one task) on your mobile phone and at the same time, your friend calls you, an interrupt is triggered upon which an interrupt service routine (ISR) signals the call processing task to wakeup. 

Mutex vs Semaphore – FAQ’s

Q.1: Can a thread acquire more than one lock (Mutex)? 

Answer:

Yes, it is possible that a thread is in need of more than one resource, hence the locks. If any lock is not available the thread will wait (block) on the lock. 

Q.2: Can a mutex be locked more than once? 

Answer:

A mutex is a lock. Only one state (locked/unlocked) is associated with it. However, a recursive mutex can be locked more than once (POSIX compliant systems), in which a count is associated with it, yet retains only one state (locked/unlocked). The programmer must unlock the mutex as many number times as it was locked. 

Q.3: What happens if a non-recursive mutex is locked more than once?

Answer:

Deadlock. If a thread that had already locked a mutex, tries to lock the mutex again, it will enter into the waiting list of that mutex, which results in a deadlock. It is because no other thread can unlock the mutex. An operating system implementer can exercise care in identifying the owner of the mutex and return if it is already locked by the same thread to prevent deadlocks. 

Q.4: Are binary semaphore and mutex the same? 

Answer:

No. We suggest treating them separately, as is explained in signaling vs locking mechanisms. But a binary semaphore may experience the same critical issues (e.g. priority inversion) associated with a mutex. We will cover these in a later article. 

A programmer can prefer mutex rather than creating a semaphore with a count of 1. 

Q.5: What is a mutex and critical section? 

Answer:

Some operating systems use the same word critical section in the API. Usually, a mutex is a costly operation due to protection protocols associated with it. At last, the objective of mutex is atomic access. There are other ways to achieve atomic access like disabling interrupts which can be much faster but ruins responsiveness. The alternate API makes use of disabling interrupts. 

Q.6: What are events? 

Answer:

The semantics of mutex, semaphore, event, critical section, etc… are the same. All are synchronization primitives. Based on their cost in using them they are different. We should consult the OS documentation for exact details. 

Q.7: Can we acquire mutex/semaphore in an Interrupt Service Routine? 

Answer:

An ISR will run asynchronously in the context of the current running thread. It is not recommended to query (blocking call) the availability of synchronization primitives in an ISR. The ISR is meant to be short, the call to mutex/semaphore may block the current running thread. However, an ISR can signal a semaphore or unlock a mutex. 

Q.8: What do we mean by “thread blocking on mutex/semaphore” when they are not available? 

Answer:

Every synchronization primitive has a waiting list associated with it. When the resource is not available, the requesting thread will be moved from the running list of processors to the waiting list of the synchronization primitive. When the resource is available, the higher priority thread on the waiting list gets the resource (more precisely, it depends on the scheduling policies). 

Q.9: Is it necessary that a thread must block always when the resource is not available? 

Answer:

Not necessary. If the design is sure ‘what has to be done when the resource is not available, the thread can take up that work (a different code branch). To support application requirements the OS provides a non-blocking API. 

For example POSIX pthread_mutex_trylock() API. When the mutex is not available the function returns immediately whereas the API pthread_mutex_lock() blocks the thread till the resource is available.



Last Updated : 30 Oct, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads