Mutex / Mutual Exclusion / Locking mechanism / Block / Sleep
-
if 1 thread is in CS other cannot enter, Return value: None, Parameters:
None
How Mutex is internally implemented?
Mutex is kernel maintained lock(a data structure) that we set before using a shared resource and release after using it.
Mutex keeps track of who currently has exclusive access to the data.
When the lock is set, no other thread can access the locked region of code.
Mutex lock will only be released by the thread who locked it.
Wake up?
When call to mutex.unlock() comes, signal is sent to scheduler. Scheduler checks all threads waiting on mutex.
if 1000 threads are waiting, wakeup call to activate 1000 comes(also called thundering herd), but scheduler wakes up 1 thread(at its discretion) & 999 falls to sleep.
Problems with Mutex
| Problem | Description |
|---|---|
| Priority Inversion |
Lower priority process is executing in Critical section, suddenly
High-Priority process is scheduled, lower-priority process is
preempted & thrown out of CS & higher priority process excecutes in
CS. Also if Higher priority thread/process is Busy Waiting then
lower priority process will never get CPU(ie never scheduled). Can PI happen on user-level threads? No, there is no preemption in user level threads. |
| Easy Deadlock | if order of mutex locking/unlocking is not correct, that can led to easy dead-lock situation. See Dead-lock example. |
| Thread holding mutex paniced | if thread-1 which holding the lock panics, whole process would panic. |
| Mutex and data are seperate Entities |
Thread-1,2 are accessing data using mutex, But thread-3 changed the
data without mutex, this should not Happen. Solutions: 1. Making mutex and data as single entity as done in Rust 2. All times keeping in mind that data should not handled outside mutex guards
|
Creating Mutex
| C++11 | POSIX | Rust |
|---|---|---|
|
|
In Rust, data and mutex are not seperate. ie data can be accessed
inside mutex only. This solves the problem which we is present in CPP
|
Wrappers around mutex
These are classes which owns mutex and provide RAII
| lock_guard (smaller=faster) | unique_lock (heavy wrt lock_guard) | |
|---|---|---|
| What |
We donot need to unlock this mutex, When lock_guard object goes out of scope, mutex is automatically unlocked |
Feature rich version of lock_guard |
| Features | Not copy construtible. Move Assignable. Because operator = is deleted. |
Move Assignable(yes), copy construtible(no) Properties lock_guard locks only when it is created. unique_lock has more features: 1. Lock/unlock again after 1st lock. 2. unique_lock be moved to other object 3. unique_lock uses a little more memory to track if it is locked. 4. deferred locking: Acquire the mutex but donot lock immediately 5. time-constrained attempts at locking: try_lock_for(), try_lock_until() 6. recursive locking |
| Code |
|
Immediate lockunique_lock <defer_lock> - Donot lock immediately. Most of deadlock problem occur because of immediate mutex locking. - defer_lock delays locking on mutex for some time. defer_lock example(Deadlock) 1 Writer, Multiple Readers
|