Skip to content

Commit 4a100ec

Browse files
committed
[concurrency] Work on mutex
- Remove global variables from mutex example, use lambdas. In order to not show using globals, I thought using lambdas to capture local variables is cleaner. I moved to C++17, since we say in the lecture now that people should alwyas use scoped_lock. I also return an exit status that captures whether or not there was a race.
1 parent d0f420b commit 4a100ec

File tree

4 files changed

+54
-33
lines changed

4 files changed

+54
-33
lines changed

code/race/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ clean:
55
rm -f *o racing *~ core racing.sol
66

77
racing : racing.cpp
8-
${CXX} -g -std=c++11 -O0 -pthread -Wall -Wextra -L. -o $@ $<
8+
${CXX} -g -std=c++17 -O0 -pthread -Wall -Wextra -L. -o $@ $<
99

1010
racing.sol : solution/racing.sol.cpp
11-
${CXX} -g -std=c++11 -O0 -pthread -Wall -Wextra -L. -o $@ $<
11+
${CXX} -g -std=c++17 -O0 -pthread -Wall -Wextra -L. -o $@ $<

code/race/racing.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,38 @@
11
#include <iostream>
22
#include <thread>
33

4-
int a = 0;
5-
6-
void inc() {
7-
a++;
8-
}
9-
10-
void inc100() {
11-
for (int i = 0; i < 100; i++)
12-
inc();
13-
}
4+
/*
5+
* This program tries to increment an integer 200 times in two threads.
6+
* Check whether the result is indeed always 200.
7+
*/
148

159
int main() {
10+
int nError = 0;
11+
1612
for (int j = 0; j < 1000; j++) {
17-
a = 0;
13+
int a = 0;
14+
15+
// Increment the variable a 100 times:
16+
auto inc100 = [&a](){
17+
for (int i = 0; i < 100; ++i) {
18+
a++;
19+
}
20+
};
21+
22+
// Run with two threads
1823
std::thread t1(inc100);
1924
std::thread t2(inc100);
20-
for (auto t: {&t1,&t2}) t->join();
25+
for (auto t : {&t1,&t2}) t->join();
26+
27+
// Check
2128
if (a != 200) {
22-
std::cout << a;
29+
std::cout << "Race: " << a << ' ';
30+
nError++;
2331
} else {
2432
std::cout << '.';
2533
}
2634
}
2735
std::cout << '\n';
36+
37+
return nError;
2838
}

code/race/solution/racing.sol.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,40 @@
22
#include <thread>
33
#include <mutex>
44

5-
int a = 0;
6-
std::mutex m;
7-
8-
void inc() {
9-
std::lock_guard<std::mutex> guard(m);
10-
a++;
11-
}
12-
13-
void inc100() {
14-
for (int i = 0; i < 100; i++)
15-
inc();
16-
}
5+
/*
6+
* This program tries to increment an integer 200 times in two threads.
7+
* We fix the race condition by locking a mutex before each increment.
8+
*/
179

1810
int main() {
11+
int nError = 0;
12+
1913
for (int j = 0; j < 1000; j++) {
20-
a = 0;
14+
int a = 0;
15+
std::mutex aMutex;
16+
17+
// Increment the variable a 100 times:
18+
auto inc100 = [&a,&aMutex](){
19+
for (int i = 0; i < 100; ++i) {
20+
std::scoped_lock lock{aMutex};
21+
a++;
22+
}
23+
};
24+
25+
// Run with two threads
2126
std::thread t1(inc100);
2227
std::thread t2(inc100);
23-
for (auto t: {&t1,&t2}) t->join();
28+
for (auto t : {&t1,&t2}) t->join();
29+
30+
// Check
2431
if (a != 200) {
25-
std::cout << a;
32+
std::cout << "Race: " << a << ' ';
33+
nError++;
2634
} else {
2735
std::cout << '.';
2836
}
2937
}
3038
std::cout << '\n';
39+
40+
return nError;
3141
}

talk/concurrency/mutexes.tex

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
\pause
9393
\begin{block}{The objects}
9494
\begin{description}[labelwidth=1.8cm]
95-
\item[std::mutex] in the mutex header
95+
\item[std::mutex] in the mutex header. \textbf{Mut}ual \textbf{ex}clusion
9696
\item[std::scoped\_lock] RAII to lock and unlock automatically
9797
\item[std::unique\_lock] same, but can be released/relocked explicitly
9898
\end{description}
@@ -114,7 +114,7 @@
114114
\frametitlecpp[17]{Mutexes and Locks}
115115
\begin{block}{Good practice}
116116
\begin{itemize}
117-
\item Always use \texttt{scoped\_lock} (\cpp11: \texttt{lock\_guard})
117+
\item Generally use \texttt{scoped\_lock} (\cpp11: \texttt{lock\_guard})
118118
\item Hold as short as possible, wrap critical section in "\texttt{\string{ \string}}"
119119
\item Only if manual control needed, use \texttt{unique\_lock}
120120
\end{itemize}
@@ -133,7 +133,7 @@
133133
\end{frame}
134134

135135
\begin{frame}[fragile]
136-
\frametitle{Mutexes}
136+
\frametitle{Mutexes and Locks}
137137
\begin{alertblock}{Exercise Time}
138138
\begin{itemize}
139139
\item Go to code/race
@@ -179,6 +179,7 @@
179179
\frametitlecpp[11]{How to avoid dead locks}
180180
\begin{block}{Possible solutions}
181181
\begin{itemize}
182+
\item \cpp17: \mintinline{cpp}{std::scoped_lock lock{m1, m2};} comes with deadlock-avoidance algorithm
182183
\item Never take several locks
183184
\begin{itemize}
184185
\item Or add master lock protecting the locking phase

0 commit comments

Comments
 (0)