-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathMutex_02_Advanced.cpp
More file actions
210 lines (152 loc) · 5.65 KB
/
Mutex_02_Advanced.cpp
File metadata and controls
210 lines (152 loc) · 5.65 KB
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// ===========================================================================
// Mutex_02_Advanced.cpp // Locking Mechanisms
// ===========================================================================
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
namespace Mutex_And_Locking_Examples {
// std::mutex object to be used by *all* code below
static std::mutex g_mutex{};
// -------------------------------------
// std::mutex
static void example_01() {
// ...
g_mutex.lock();
// critical section here
// ...
g_mutex.unlock();
}
// -------------------------------------
// std::lock_guard
static void example_02() {
// ...
{
// 'g_mutex.lock()' is automatically called
// at the construction of the 'std::lock_guard'
std::lock_guard<std::mutex> guard{ g_mutex };
// critical section here
// ...
// 'g_mutex.unlock()' is automatically called here
// at the destruction of the 'std::lock_guard'
}
// ...
}
// -------------------------------------
// std::unique_lock
static void example_03_01() {
// basic std::unique_lock usage
{
// 'g_mutex.lock()' is automatically called
// at the construction of the 'std::unique_lock'
std::unique_lock<std::mutex> guard{ g_mutex };
// critical section here
// ...
// 'g_mutex.unlock()' is automatically called here
// at the destruction of the 'std::unique_lock'
}
}
static void example_03_02() {
// multiple critical sections
{
// 'g_mutex.lock()' is automatically called
// at the construction of the 'std::unique_lock'
std::unique_lock<std::mutex> guard{ g_mutex };
// first critical section here
// ...
guard.unlock();
// do non-critical stuff here
// ...
guard.lock();
// second critical section here
// ...
// 'g_mutex.unlock()' is automatically called here
// at the destruction of the 'std::unique_lock'
}
}
static void example_03_03() {
// choose to NOT automatically lock at construction
{
// 'g_mutex.lock()' is NOT automatically called
// at the construction of the 'std::unique_lock'
std::unique_lock<std::mutex> guard{ g_mutex, std::defer_lock };
// do non-critical stuff here
// ...
guard.lock();
// critical section here
// ...
guard.unlock();
// do non-critical stuff here
// ...
guard.lock();
// second critical section here
// ...
// 'g_mutex.unlock()' is automatically called
// at the destruction of the 'std::unique_lock'
// (guard may be locked or unlocked: no exception is called during destructor invocation !)
}
}
// -------------------------------------
// std::scoped_lock
static std::mutex g_mutex1{};
static std::mutex g_mutex2{};
static std::mutex g_mutex3{};
static void example_04_01() {
// basic scoped lock usage on multiple mutexes at once
{
// 'lock()' is automatically simultaneously called
// on all mutexes here at the construction of the 'std::scoped_lock'
std::scoped_lock guard{ g_mutex1, g_mutex2, g_mutex3 };
// critical section here
// ...
// 'unlock()' is automatically simultaneously called on all mutexes
// here at the destruction of the `std::scoped_lock` object
}
}
static void example_04_02() {
// equivalent to example above, but C++11 compatible
{
// 1. explicitly lock all mutexes at once
std::lock(g_mutex1, g_mutex2, g_mutex3);
// 2. Now pass their ownership individually to `std::lock_guard` objects
// to auto-unlock them at the termination of this scope.
// Creating a `std::lock_guard` with the `std::adopt_lock` parameter means,
// that the ownership of the mutex is acquired without attempting to lock it!
std::lock_guard<std::mutex> lock1{ g_mutex1, std::adopt_lock };
std::lock_guard<std::mutex> lock2{ g_mutex2, std::adopt_lock };
std::lock_guard<std::mutex> lock3{ g_mutex3, std::adopt_lock };
// critical section here
// ...
// 'unlock()' is automatically simultaneously called on all mutexes
// here at the destruction of the `std::lock_guard` objects
}
}
static void example_04_03() {
// another C++ 11 compatible example
{
// explicitly lock all mutexes at once
std::lock(g_mutex1, g_mutex2, g_mutex3);
// critical section here
// ...
// unlock each mutex individually now
g_mutex1.unlock();
g_mutex2.unlock();
g_mutex3.unlock();
}
}
}
void test_advanced_mutex()
{
using namespace Mutex_And_Locking_Examples;
example_01();
example_02();
example_03_01();
example_03_02();
example_03_03();
example_04_01();
example_04_02();
example_04_03();
}
// ===========================================================================
// End-of-File
// ===========================================================================