What is the difference between lock, mutex and semaphore?

I've heard these words related to concurrent programming, but what's the difference between lock, mutex and semaphore?

1,640 2 2 gold badges 15 15 silver badges 33 33 bronze badges asked Feb 25, 2010 at 9:03 6,751 3 3 gold badges 17 17 silver badges 5 5 bronze badges Commented Jun 30, 2015 at 8:42 The best explanation I have ever seen: crystal.uta.edu/~ylei/cse6324/data/semaphore.pdf Commented Jul 26, 2016 at 8:08 Possible duplicate of Difference between binary semaphore and mutex – user177800 Commented Dec 7, 2017 at 16:10

10 Answers 10

A lock allows only one thread to enter the part that's locked and the lock is not shared with any other processes, a lock must be released by that same thread that acquired it. Some locks can be acquired multiple times by the same thread without causing a deadlock, but must be released the same amount of times.

A mutex is the same as a lock but it can be system wide (shared by multiple processes).

A semaphore does the same as a mutex but allows x number of threads to enter, this can be used for example to limit the number of cpu, io or ram intensive tasks running at the same time.

For a more detailed post about the differences between mutex and semaphore read here.

A semaphore kan be acquired by one thread and released by a different thread, this is not possible with a normal lock.

You also have read/write locks that allows either unlimited number of readers or 1 writer at any given time.

The descriptions are from a .NET perspective and might not be 100% accurate for all OS/Languages.

answered Feb 25, 2010 at 9:21 38.1k 39 39 gold badges 148 148 silver badges 206 206 bronze badges

@mertinan i can't say i ever heard about it, but this is what wikipedia says "Latch (database), (a relatively short-lived) lock on a system data-structure like an index"

Commented Jun 20, 2012 at 6:12 Monitor allows to wait for a certain condition (e.g. when lock is released), "monitors". Commented Nov 14, 2013 at 19:35

A semaphore is not the same as a mutex. They are used very differently and also have different properties (namely regarding ownership). See for example barrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphore for details

Commented Apr 28, 2014 at 5:34 @nanoquack feel free to edit my answer if you feel that it is misleading or incorrect. Commented Apr 28, 2014 at 6:44

For a clearer distinction between mutex and semaphore, in nanoquack's link, The key paragraph is "The correct use of a semaphore is for signaling from one task to another. A mutex is meant to be taken and released, always in that order, by each task that uses the shared resource it protects. By contrast, tasks that use semaphores either signal or wait—not both."

Commented Feb 2, 2017 at 5:14

There are a lot of misconceptions regarding these words.

This is from a previous post (https://stackoverflow.com/a/24582076/3163691) which fits superb here:

1) Critical Section= User object used for allowing the execution of just one active thread from many others within one process. The other non selected threads (@ acquiring this object) are put to sleep.

[No interprocess capability, very primitive object].

2) Mutex Semaphore (aka Mutex)= Kernel object used for allowing the execution of just one active thread from many others, among different processes. The other non selected threads (@ acquiring this object) are put to sleep. This object supports thread ownership, thread termination notification, recursion (multiple 'acquire' calls from same thread) and 'priority inversion avoidance'.

[Interprocess capability, very safe to use, a kind of 'high level' synchronization object].

3) Counting Semaphore (aka Semaphore)= Kernel object used for allowing the execution of a group of active threads from many others. The other non selected threads (@ acquiring this object) are put to sleep.

[Interprocess capability however not very safe to use because it lacks following 'mutex' attributes: thread termination notification, recursion?, 'priority inversion avoidance'?, etc].

4) And now, talking about 'spinlocks', first some definitions:

Critical Region= A region of memory shared by 2 or more processes.

Lock= A variable whose value allows or denies the entrance to a 'critical region'. (It could be implemented as a simple 'boolean flag').

Busy waiting= Continuosly testing of a variable until some value appears.

Spin-lock (aka Spinlock)= A lock which uses busy waiting. (The acquiring of the lock is made by xchg or similar atomic operations).

[No thread sleeping, mostly used at kernel level only. Ineffcient for User level code].

As a last comment, I am not sure but I can bet you some big bucks that the above first 3 synchronizing objects (#1, #2 and #3) make use of this simple beast (#4) as part of their implementation.

Have a good day!.

References:

-Real-Time Concepts for Embedded Systems by Qing Li with Caroline Yao (CMP Books).

-Modern Operating Systems (3rd) by Andrew Tanenbaum (Pearson Education International).

-Programming Applications for Microsoft Windows (4th) by Jeffrey Richter (Microsoft Programming Series).

answered Jul 5, 2014 at 13:40 2,543 1 1 gold badge 17 17 silver badges 17 17 bronze badges

Actually critical section is not a kernel object, thus more lightweight and incapable of synchronizing across processes.

Commented May 30, 2015 at 10:51 @ Vladislavs Burakovs: You are right! Forgive my redaction. I'll fix it for the sake of coherence. Commented Sep 17, 2015 at 15:28

For a clearer distinction between mutex and semaphore, as nanoquack mentions elsewhere, see barrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphore - The key paragraph is "The correct use of a semaphore is for signaling from one task to another. A mutex is meant to be taken and released, always in that order, by each task that uses the shared resource it protects. By contrast, tasks that use semaphores either signal or wait—not both."

Commented Feb 2, 2017 at 5:13

Re conjecture other lock mechanisms build on [inefficient] spinlock: unlikely; AFAIK only need some atomic operations plus sleep queues. Even where spinlock is needed inside kernel, modern solutions minimize its impact as described in Wikipedia - Spinlock - Alternatives - ".. use a hybrid approach called "adaptive mutex". The idea is to use a spinlock when trying to access a resource locked by a currently-running thread, but to sleep if the thread is not currently running. (The latter is always the case on single-processor systems.)"

Commented Feb 2, 2017 at 5:28

A "critical section" in general is actually the piece of code that accesses a shared resource and must do so in an atomic manner. Now there are also "critical section objects" in Windows which are light weight mutexes that can be used only in the same process. They allow more efficient implementation of critical sections then mutex objects, because no kernel transition happens unless there is contention.

Commented Apr 5, 2020 at 10:36

Most problems can be solved using (i) just locks, (ii) just semaphores, . or (iii) a combination of both! As you may have discovered, they're very similar: both prevent race conditions, both have acquire() / release() operations, both cause zero or more threads to become blocked/suspended. Really, the crucial difference lies solely on how they lock and unlock.

For both locks/semaphores, trying to call acquire() while the primitive is in state 0 causes the invoking thread to be suspended. For locks - attempts to acquire the lock is in state 1 are successful. For semaphores - attempts to acquire the lock in states are successful.

For locks in state state 0, if same thread that had previously called acquire() , now calls release, then the release is successful. If a different thread tried this -- it is down to the implementation/library as to what happens (usually the attempt ignored or an error is thrown). For semaphores in state 0, any thread can call release and it will be successful (regardless of which thread previous used acquire to put the semaphore in state 0).

From the preceding discussion, we can see that locks have a notion of an owner (the sole thread that can call release is the owner), whereas semaphores do not have an owner (any thread can call release on a semaphore).

What causes a lot of confusion is that, in practice they are many variations of this high-level definition.

Important variations to consider:

These depends on your book / lecturer / language / library / environment.
Here's a quick tour noting how some languages answer these details.

C, C++ (pthreads)

python (threading.py)

Java (java.util.concurrent)

In theory, semaphores are often discussed, but in practice, semaphores aren't used so much. A semaphore only hold the state of one integer, so often it's rather inflexible and many are needed at once -- causing difficulty in understanding code. Also, the fact that any thread can release a semaphore is sometimes undesired. More object-oriented / higher-level synchronization primitives / abstractions such as "condition variables" and "monitors" are used instead.

2,990 30 30 silver badges 35 35 bronze badges answered Jan 28, 2017 at 15:08 James Lawson James Lawson 8,528 51 51 silver badges 49 49 bronze badges

Definitively the most thorough answer. It would be helpful to have examples. For example can a semaphore lock customer master file for reading shared, or lock everyone out for nightly updates? Can a semaphore lock a customer number for exclusive update, or lock customer number for shared reading? etc. Or should applications create their own semaphore file and not use system semaphores?

Commented Oct 7, 2020 at 2:08

"the fact that any thread can release a semaphore is sometimes undesired" The fact that a different thread will decrement a semaphore is the defining characteristic of a semaphore. It's what distinguishes a semaphore from a mutex/lock.

Commented Nov 9, 2020 at 20:00

A mutex is the same as a lock (the term is not used often in Java) - That's the point that tons of articles did not explain well

Commented Apr 13, 2021 at 17:26

Take a look at Multithreading Tutorial by John Kopplin.

In the section Synchronization Between Threads, he explain the differences among event, lock, mutex, semaphore, waitable timer

A mutex can be owned by only one thread at a time, enabling threads to coordinate mutually exclusive access to a shared resource

Critical section objects provide synchronization similar to that provided by mutex objects, except that critical section objects can be used only by the threads of a single process

Another difference between a mutex and a critical section is that if the critical section object is currently owned by another thread, EnterCriticalSection() waits indefinitely for ownership whereas WaitForSingleObject() , which is used with a mutex, allows you to specify a timeout

A semaphore maintains a count between zero and some maximum value, limiting the number of threads that are simultaneously accessing a shared resource.

answered Jul 25, 2013 at 8:58 onmyway133 onmyway133 47.6k 32 32 gold badges 265 265 silver badges 270 270 bronze badges

I will try to cover it with examples:

Lock: One example where you would use lock would be a shared dictionary into which items (that must have unique keys) are added.
The lock would ensure that one thread does not enter the mechanism of code that is checking for item being in dictionary while another thread (that is in the critical section) already has passed this check and is adding the item. If another thread tries to enter a locked code, it will wait (be blocked) until the object is released.

private static readonly Object obj = new Object(); lock (obj) //after object is locked no thread can come in and insert item into dictionary on a different thread right before other thread passed the check. < if (!sharedDict.ContainsKey(key)) < sharedDict.Add(item); >> 

Semaphore: Let's say you have a pool of connections, then an single thread might reserve one element in the pool by waiting for the semaphore to get a connection. It then uses the connection and when work is done releases the connection by releasing the semaphore.

using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace TheNightclub < public class Program < public static Semaphore Bouncer < get; set; >public static void Main(string[] args) < // Create the semaphore with 3 slots, where 3 are available. Bouncer = new Semaphore(3, 3); // Open the nightclub. OpenNightclub(); >public static void OpenNightclub() < for (int i = 1; i > public static void Guest(object args) < // Wait to enter the nightclub (a semaphore to be released). Console.WriteLine("Guest is waiting to entering nightclub.", args); Bouncer.WaitOne(); // Do some dancing. Console.WriteLine("Guest is doing some dancing.", args); Thread.Sleep(500); // Let one guest out (release one semaphore). Console.WriteLine("Guest is leaving the nightclub.", args); Bouncer.Release(1); > > > 

Mutex It is pretty much Semaphore(1,1) and often used globally (application wide otherwise arguably lock is more appropriate). One would use global Mutex when deleting node from a globally accessible list (last thing you want another thread to do something while you are deleting the node). When you acquire Mutex if different thread tries to acquire the same Mutex it will be put to sleep till SAME thread that acquired the Mutex releases it.

class SingleGlobalInstance : IDisposable < public bool hasHandle = false; Mutex mutex; private void InitMutex() < string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString(); string mutexId = string.Format("Global\\>>", appGuid); mutex = new Mutex(false, mutexId); var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow); var securitySettings = new MutexSecurity(); securitySettings.AddAccessRule(allowEveryoneRule); mutex.SetAccessControl(securitySettings); > public SingleGlobalInstance(int timeOut) < InitMutex(); try < if(timeOut < 0) hasHandle = mutex.WaitOne(Timeout.Infinite, false); else hasHandle = mutex.WaitOne(timeOut, false); if (hasHandle == false) throw new TimeoutException("Timeout waiting for exclusive access on SingleInstance"); >catch (AbandonedMutexException) < hasHandle = true; >> public void Dispose() < if (mutex != null) < if (hasHandle) mutex.ReleaseMutex(); mutex.Dispose(); >> > 
using (new SingleGlobalInstance(1000)) //1000ms timeout on global lock < //Only 1 of these runs at a time GlobalNodeList.Remove(node) >

Hope this saves you some time.