2

I am wondering if the Mutex object busy waits or does it context switch out (i.e. does the thread owning the mutex go to sleep and get woken up later by an interrupt), or is it architecture dependent (i.e. number of cores your machine has)? I am hoping that it actually does a context switch out. Thank you in advance.

reservoirman
  • 119
  • 1
  • 11

2 Answers2

8

As per the documentation, Mutex.WaitOne "Blocks the current thread until the current WaitHandle receives a signal", which means it's put to sleep.


Internally, WaitHandle.WaitOne will call WaitForSingleObjectEx from the Windows API, which:

Waits until the specified object is in the signaled state, an I/O completion routine or asynchronous procedure call (APC) is queued to the thread, or the time-out interval elapses.

Also, according to another document on Context Switches

When a running thread needs to wait, it relinquishes the remainder of its time slice.

dcastro
  • 66,540
  • 21
  • 145
  • 155
  • 1
    well, *SpinWait* also blocks the current thread - but without context switch. I guess the *WaitHandle* part is what OP is asking about. – Agent_L May 26 '15 at 14:11
  • @Agent_L The documentation for [`Thread.SpinWait`](https://msdn.microsoft.com/en-us/library/system.threading.thread.spinwait%28v=vs.110%29.aspx) describes it as "Causes a thread to wait the number of times defined by the iterations parameter". Notice the word "block" is mentioned nowhere in the document. I think it's safe to assume that "block" here means "putting the thread to sleep". – dcastro May 26 '15 at 14:25
  • 2
    @dcastro: -1. You didn't answer the asker's question. The core of the question is *how* mutex achieves blocking, and what 'blocking' means here. It is not safe to to assume that blocking == sleeping, since burning CPU and being removed from the run queue are both valid ways of 'blocking'. As a matter of fact, modern mutex implementations, **which have platform-dependent* characteristics, tend to use both as part of a hybrid approach - spinwaits are used initially to keep the thread on the cpu if uncontested, sleeping otherwise. – antiduh May 26 '15 at 14:41
  • @antiduh I've added some more detail to my answer, hopefully it makes it clear that "blocking" does not entail busy waiting. – dcastro May 26 '15 at 15:16
  • @dcastro - Then your answer is misleading or incorrect. `Mutex.WaitOne()`, as implemented by the Microsoft .Net framework, does indeed use busy waits - it's implemented by an Adaptive Mutex. It'll busy-wait for a short while, trying to grab the lock. If it is unable to grab the lock before its thread quantum expires, it'll stop busy waiting and instead sleep. **A mutex can block without sleeping**. – antiduh Aug 23 '17 at 20:01
6

A good answer to draw from is here: When should one use a spinlock instead of a mutex?

The answer is that it depends. The Mutex class in .Net is typically backed by the operating system, since it is a lock that can be shared between multiple processes; it is not intended to be used only within a single process.

This means that we're at the mercy of our operating system's implementation. Most modern OSes, including Windows, implement adaptive mutexes for multi-core machines.

Drawing from the above answer, we learn that implementing locking by suspending the thread is often very expensive, since it requires at least 2 context switches. On a multi-core system, we can avoid some context switches by attempting to spin-wait initially to acquire the lock - if the lock is lightly contended, you'll likely acquire the lock in the spinwait, and thus never suffer the penalty of a context switch/thread suspension. In the case that the timeout expires while the spinwait is occurring, the lock will downgrade to full thread suspension to keep from wasting too much cpu.

None of this makes sense on a single-core machine, since you'd just be burning CPU while the holder of the lock is waiting to run to finish the work it needs to do in order to release the lock. Adaptive locks are not used on single-core machines.

So, to directly answer your question - it is likely that the Mutex class does both - it'll busy-wait (spin-wait) for a short while to see if it can acquire the mutex without performing a context switch, and if it can't do so in the short amount of time it allows itself, it'll suspend the thread. It's important to note that the amount of time it'll spinwait for is usually very short, and that overall, this strategy can significantly reduce total CPU usage or increase overall lock throughput. So, even though we're burning CPU spin-waiting, we'll probably save more CPU overall.

In context of .Net, the Mutex class provides mutual exclusion, but is meant to be used between multiple processes, and thus tends to be quite slow. Specifically, the implementation of the Mutex class in the Microsoft .Net Framework, the .Net Mutex class uses the Win32 Mutex object.

Do note that the details may change depending on which implementation of .Net you're using, and on which operating system. I've tried to provide a .Net/Microsoft/Windows-centric treatment of the topic since that is the most common circumstance.

As an aside, if you only need locking within a single process, the Monitor class, or its keyword lock, should be used instead. A similar dichotomy exists for semaphores - the Semaphore class is, in the end, implemented by the operating system - it can be used for inter-process communication and thus tends to be slow; the SemaphoreSlim class is implemented natively in .Net, can be used only within a single process, and tends to be faster. On this point, a good msdn article to read is Overview of Synchronization Primitives.

Community
  • 1
  • 1
antiduh
  • 11,853
  • 4
  • 43
  • 66