Introduction Shared Mutex
In my previous article, I wrote about mutex library which provided mutual exclusiveness and how they avoid race conditions by allowing only one thread to access data simultaneously.
However here,shared mutex class adds the ability to provide shared access to the mutex.
This allows one to, for example, provide read access to a resource by multiple threads, while a writing thread would still be able to gain exclusive access.
While a regular mutex exposes 3 methods: lock
, unlock
and try_lock
,
Shared Mutex however adds 3 more methods::
- lock_shared
- try_lock_shared
- unlock_shared
where shared means several threads can share ownership of the same mutex.
Point to note::
- If one thread has acquired the exclusive lock (through lock, try_lock), no other threads can acquire the lock (including the shared).
- If one thread has acquired the shared lock (through lock_shared, try_lock_shared), no other thread can acquire the exclusive lock, but can acquire the shared lock.
- Only when the exclusive lock has not been acquired by any thread, the shared lock can be acquired by multiple threads.
- Within one thread, only one lock (shared or exclusive) can be acquired at the same time.
Shared Mutex is useful in situations where we may allow multiple parallel readers or one writer to operate on a block of data.
The member functions are same as mentioned in the previous article,with the additon of the shared functions:
- lock_shared - locks the mutex for shared ownership, blocks if the mutex is not available
- try_lock_shared - tries to lock the mutex for shared ownership, returns if the mutex is not available
- unlock_shared - unlocks the mutex (shared ownership).
A Sample Program
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| #include <iostream>
#include <thread>
#include <shared_mutex>
int value = 0;
std::shared_mutex mutex;
// Reads the value and sets v to that value
void readValue(int& v) {
mutex.lock_shared();
// Simulate some latency/time to run
std::this_thread::sleep_for(std::chrono::seconds(1));
v = value;
mutex.unlock_shared();
}
// Sets value to v
void setValue(int v) {
mutex.lock();
// Simulate some latency/time to run
std::this_thread::sleep_for(std::chrono::seconds(1));
value = v;
mutex.unlock();
}
int main() {
int read1;
int read2;
int read3;
std::thread t1(readValue, std::ref(read1));
std::thread t2(readValue, std::ref(read2));
std::thread t3(readValue, std::ref(read3));
std::thread t4(setValue, 1);
t1.join();
t2.join();
t3.join();
t4.join();
std::cout << read1 << "\n";
std::cout << read2 << "\n";
std::cout << read3 << "\n";
std::cout << value << "\n";
}
Here if we do not use shared mutex,the profram takes 4 sec to run as each thread takes around 1 sec to run, however using shared mutex reduces the time taken to 2 sec as it allows threads t1 , t2 and t3 can access the data at the same time. The only thread that will be waiting for 1 second is t4 .
|
Comments