What is the difference between mutex and critical section?

105,951

Solution 1

For Windows, critical sections are lighter-weight than mutexes.

Mutexes can be shared between processes, but always result in a system call to the kernel which has some overhead.

Critical sections can only be used within one process, but have the advantage that they only switch to kernel mode in the case of contention - Uncontended acquires, which should be the common case, are incredibly fast. In the case of contention, they enter the kernel to wait on some synchronization primitive (like an event or semaphore).

I wrote a quick sample app that compares the time between the two of them. On my system for 1,000,000 uncontended acquires and releases, a mutex takes over one second. A critical section takes ~50 ms for 1,000,000 acquires.

Here's the test code, I ran this and got similar results if mutex is first or second, so we aren't seeing any other effects.

HANDLE mutex = CreateMutex(NULL, FALSE, NULL);
CRITICAL_SECTION critSec;
InitializeCriticalSection(&critSec);

LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
LARGE_INTEGER start, end;

// Force code into memory, so we don't see any effects of paging.
EnterCriticalSection(&critSec);
LeaveCriticalSection(&critSec);
QueryPerformanceCounter(&start);
for (int i = 0; i < 1000000; i++)
{
    EnterCriticalSection(&critSec);
    LeaveCriticalSection(&critSec);
}

QueryPerformanceCounter(&end);

int totalTimeCS = (int)((end.QuadPart - start.QuadPart) * 1000 / freq.QuadPart);

// Force code into memory, so we don't see any effects of paging.
WaitForSingleObject(mutex, INFINITE);
ReleaseMutex(mutex);

QueryPerformanceCounter(&start);
for (int i = 0; i < 1000000; i++)
{
    WaitForSingleObject(mutex, INFINITE);
    ReleaseMutex(mutex);
}

QueryPerformanceCounter(&end);

int totalTime = (int)((end.QuadPart - start.QuadPart) * 1000 / freq.QuadPart);

printf("Mutex: %d CritSec: %d\n", totalTime, totalTimeCS);

Solution 2

From a theoretical perspective, a critical section is a piece of code that must not be run by multiple threads at once because the code accesses shared resources.

A mutex is an algorithm (and sometimes the name of a data structure) that is used to protect critical sections.

Semaphores and Monitors are common implementations of a mutex.

In practice there are many mutex implementation availiable in windows. They mainly differ as consequence of their implementation by their level of locking, their scopes, their costs, and their performance under different levels of contention. See CLR Inside Out - Using concurrency for scalability for an chart of the costs of different mutex implementations.

Availiable synchronization primitives.

The lock(object) statement is implemented using a Monitor - see MSDN for reference.

In the last years much research is done on non-blocking synchronization. The goal is to implement algorithms in a lock-free or wait-free way. In such algorithms a process helps other processes to finish their work so that the process can finally finish its work. In consequence a process can finish its work even when other processes, that tried to perform some work, hang. Usinig locks, they would not release their locks and prevent other processes from continuing.

Solution 3

In addition to the other answers, the following details are specific to critical sections on windows:

  • in the absence of contention, acquiring a critical section is as simple as an InterlockedCompareExchange operation
  • the critical section structure holds room for a mutex. It is initially unallocated
  • if there is contention between threads for a critical section, the mutex will be allocated and used. The performance of the critical section will degrade to that of the mutex
  • if you anticipate high contention, you can allocate the critical section specifying a spin count.
  • if there is contention on a critical section with a spin count, the thread attempting to acquire the critical section will spin (busy-wait) for that many processor cycles. This can result in better performance than sleeping, as the number of cycles to perform a context switch to another thread can be much higher than the number of cycles taken by the owning thread to release the mutex
  • if the spin count expires, the mutex will be allocated
  • when the owning thread releases the critical section, it is required to check if the mutex is allocated, if it is then it will set the mutex to release a waiting thread

In linux, I think that they have a "spin lock" that serves a similar purpose to the critical section with a spin count.

Solution 4

Critical Section and Mutex are not Operating system specific, their concepts of multithreading/multiprocessing.

Critical Section Is a piece of code that must only run by it self at any given time (for example, there are 5 threads running simultaneously and a function called "critical_section_function" which updates a array... you don't want all 5 threads updating the array at once. So when the program is running critical_section_function(), none of the other threads must run their critical_section_function.

mutex* Mutex is a way of implementing the critical section code (think of it like a token... the thread must have possession of it to run the critical_section_code)

Solution 5

A mutex is an object that a thread can acquire, preventing other threads from acquiring it. It is advisory, not mandatory; a thread can use the resource the mutex represents without acquiring it.

A critical section is a length of code that is guaranteed by the operating system to not be interupted. In pseudo-code, it would be like:

StartCriticalSection();
    DoSomethingImportant();
    DoSomeOtherImportantThing();
EndCriticalSection();
Share:
105,951
Admin
Author by

Admin

Updated on December 12, 2020

Comments

  • Admin
    Admin over 3 years

    Please explain from Linux, Windows perspectives?

    I am programming in C#, would these two terms make a difference. Please post as much as you can, with examples and such....

    Thanks

  • configurator
    configurator about 15 years
    Also, mutexes can be shared across processes.
  • Promit
    Promit about 15 years
    Unfortunately a Window critical section involves doing a CAS operation in kernel mode, which is massively more expensive than the actual interlocked operation. Also, Windows critical sections can have spin counts associated with them.
  • Michael
    Michael about 15 years
    That is definitly not true. CAS can be done with cmpxchg in user mode.
  • Michael
    Michael about 15 years
    I think the poster was talking about user mode synchronization primitives, like a win32 Critical section object, which just provides mutual exclusion. I don't know about Linux, but Windows kernel has critical regions which behave like you describe - non-interruptable.
  • Adam Rosenfield
    Adam Rosenfield about 15 years
    I don't know why you got downvoted. There's the concept of a critical section, which you've described correctly, which is different from the Windows kernel object called a CriticalSection, which is a type of mutex. I believe the OP was asking about the latter definition.
  • 1800 INFORMATION
    1800 INFORMATION about 15 years
    I thought the default spin count was zero if you called InitializeCriticalSection - you have to call InitializeCriticalSectionAndSpinCount if you want a spin count applied. Do you have a reference for that?
  • Mikko Rantanen
    Mikko Rantanen about 15 years
    At least I got confused by the language agnostic tag. But in any case this is what we get for Microsoft naming their implementation the same as their base class. Bad coding practice!
  • Jason Coco
    Jason Coco about 15 years
    Well, he asked for as much detail as possible, and specifically said Windows and Linux so sounds like concepts are good. +1 -- didn't understand the -1 either :/
  • user1925801
    user1925801 almost 15 years
    Not sure if this relates or not (since I haven't compiled and tried your code), but I've found that calling WaitForSingleObject with INFINITE results in poor performance. Passing it a timeout value of 1 then looping while checking it's return has made a huge difference in the performance of some of my code. This is mostly in the context of waiting for an external process handle, however... Not a mutex. YMMV. I'd be interested in seeing how mutex performs with that modification. The resulting time difference from this test seems bigger than should be expected.
  • TL36
    TL36 over 14 years
    What happens when a program that initializes and uses a Mutex object, crashes? Does the Mutex object gets automatically deallocated? No, I would say. Right?
  • Michael
    Michael over 14 years
    Kernel objects have a reference count. Closing a handle to an object decrements the reference count and when it reaches 0 the object is freed. When a process crashes, all of its handles are automatically closed, so a mutex that only that process has a handle to would be automatically deallocated.
  • Anirudh Ramanathan
    Anirudh Ramanathan over 11 years
    Seeing the accepted answer, I was thinking maybe I remembered the concept of critical sections wrong, till I saw that Theoretical Perspective you wrote. :)
  • Tim Post
    Tim Post over 11 years
    Practical lock free programming is like Shangri La, except it exists. Keir Fraser's paper (PDF) explores this rather interestingly (going back to 2004). And we're still struggling with it in 2012. We suck.
  • dss539
    dss539 about 11 years
    @TroyHoward aren't you basically just spin locking at that point?
  • regnarg
    regnarg over 9 years
    The reasons for this distinction are probaly mainly historical. It is not hard to implement locking that is as fast as CriticalSection in the uncontended case (few atomic instructions, no syscalls), yet works across processes (with a piece of shared memory). See e.g. Linux futexes.
  • Stevens Miller
    Stevens Miller over 7 years
    @TroyHoward try forcing your CPU to run at 100% all the time and see if INFINITE works better. The power strategy can take as long as 40ms on my machine (Dell XPS-8700) to crawl back up to full speed after it decides to slow down, which it may not do if you sleep or wait for only a millisecond.
  • Sisir
    Sisir over 5 years
    And this is the reason why Critical Section objects are process bound, on the other hand mutexes can be shared across processes.
  • N.S.
    N.S. about 5 years
    I'm not sure I understand what's being demonstrated here. Generally, entering a critical section requires acquring some kind of semaphore. Are you saying that behind the scenes, the O/S has an efficient way of implementing this critical section behavior without requiring mutexes?
  • Ky -
    Ky - over 3 years
    To my untrained eye, this does not appear to answer the question about mutex and critical section. If you add some explanation for how this relates to the question, then it'll attract more upvotes and remain open. Otherwise, it'll probably be removed as not being an answer to this question.