-
Notifications
You must be signed in to change notification settings - Fork 3
/
locking.cpp
59 lines (46 loc) · 1.5 KB
/
locking.cpp
1
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
* Objective: Demonstrate different types of locking.
*
* Why do we require locking?
*
* 1. If there are multiple threads doing console output, the output would be gibberish
* because multiple threads are writing to the console at the same time.
*
* 2. If multiple threads are incrementing the same value without locking, there will be data race.
* It means the value may be incremented just once after being called by multiple threads which is not desirable.
*
* Tips:
* 1. Lock resources that you're going to change/write.
* 2. Read-only resources do not need to be locked.
* */
#include <thread>
#include <iostream>
#include <mutex>
using namespace std;
// Mutex must be global
mutex m1;
void some_op_1() {
// do some task
this_thread::sleep_for(chrono::milliseconds(rand() % 100));
m1.lock();
// do some more task
cout << "Resource locked" << endl;
// If any code before unlocking throws exception, then mutex is never unlocked.
m1.unlock();
// If you forget to unlock the mutex or an exception is thrown, other threads can't access the resource.
}
// Using lock_guard, unique_lock or scoped_lock is preferred over using mutex lock and unlock.
void some_op_2() {
unique_lock<mutex> lock(m1);
// do some more task
cout << "Resource locked" << endl;
// All of these work: lock_guard, scoped_lock, unique_lock
// The locks are unlocked automatically when they go out of scope.
}
int main() {
thread t1(some_op_1);
thread t2(some_op_2);
t1.join();
t2.join();
return 0;
}