forked from hsf-training/cpluspluscourse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcondition.tex
129 lines (122 loc) · 4.34 KB
/
condition.tex
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
\subsection[condition]{Condition Variables}
\begin{frame}[fragile]
\frametitlecpp[11]{Condition variables}
\begin{block}{Communicating between threads}
\begin{itemize}
\item Take the case where threads are waiting for other thread(s)
\item \cppinline{std::condition_variable}
\begin{itemize}
\item from \cppinline{<condition_variable>} header
\end{itemize}
\item Allows for a thread to sleep (= conserve CPU time) until a given condition is satisfied
\end{itemize}
\end{block}
\pause
\begin{block}{Usage}
\begin{itemize}
\item Use RAII-style locks to protect shared data
\item \cppinline{wait()} will block until the condition is met
\begin{itemize}
\item you can have several waiters sharing the same mutex
\end{itemize}
\item \cppinline{notify_one()} will wake up one waiter
\item \cppinline{notify_all()} will wake up all waiters
\end{itemize}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitlecpp[17]{Using condition variables: notify}
\begin{block}{Producer side: providing data to waiting threads}
\begin{itemize}
\item Protect data with a mutex, and use condition variable to notify consumers
\item Optimal use: don't hold lock while notifying
\begin{itemize}
\item waiting threads would be blocked
\end{itemize}
\end{itemize}
\end{block}
\begin{exampleblock}{}
\begin{cppcode*}{}
std::mutex mutex;
std::condition_variable cond;
Data data;
std::thread producer([&](){
{
std::scoped_lock lock{mutex};
data = produceData(); // may take long ...
}
cond.notify_all();
});
\end{cppcode*}
\end{exampleblock}
\end{frame}
\begin{frame}[fragile]
\frametitlecpp[11]{Using condition variables: wait}
\vspace{-1.2\baselineskip}
\begin{overprint}
\onslide<1>
\begin{block}{Mechanics of wait}
\begin{itemize}
\item Many threads can wait for shared data
\item Pass \cppinline{unique_lock} and optional predicate to \cppinline{wait()}
\item \cppinline{wait()} keeps threads asleep while predicate is \cppinline{false}
\begin{itemize}
\item Threads might wake up spuriously, but \cppinline{wait()} returns only when lock available \emph{and} predicate \cppinline{true}
\end{itemize}
\item \cppinline{wait()} will only lock when necessary; unlocked while sleeping
\end{itemize}
\end{block}
\onslide<2->
\begin{block}{Waiting / waking up}
\begin{itemize}
\item When \cppinline{notify_all()} is called, threads wake up
\item Threads try to lock mutex, and evaluate predicate
\item One thread succeeds to acquire mutex, starts processing data
\item {\color{red} Problem}: One thread holds mutex, other threads are blocked!
\end{itemize}
\end{block}
\end{overprint}
\begin{alertblock}{Na\"ive waiting}
\begin{cppcode*}{highlightlines=3}
auto processData = [&](){
std::unique_lock<std::mutex> lock{mutex};
cond.wait(lock, [&](){ return data.isReady(); });
process(data);
};
\end{cppcode*}
\end{alertblock}
\end{frame}
\begin{frame}[fragile]
\frametitlecpp[11]{Using condition variables: correct wait}
\begin{block}{Waiting / waking up}
\begin{itemize}
\item {\color{green!50!black} Solution:} Put locking and waiting in a scope
\item Threads will one-by-one wake up, acquire lock, evaluate predicate, release lock
\end{itemize}
\end{block}
\begin{exampleblock}{Correct waiting}
\begin{cppcode*}{}
auto processData = [&](){
{
std::unique_lock<std::mutex> lock{mutex};
cond.wait(lock, [&](){ return data.isReady(); });
}
process(data);
};
std::thread t1{processData}, t2{processData}, ...;
for (auto t : {&producer, &t1, &t2, ...}) t->join();
\end{cppcode*}
\end{exampleblock}
\end{frame}
\begin{frame}[fragile]
\frametitle{Condition variables}
\begin{exerciseWithShortcut}{Condition variables}{Condition vars}
\begin{itemize}
\item Go to \texttt{exercises/condition\_variable}
\item Look at the code and run it\\
See that it has a race condition
\item Fix the race condition in the usage of the condition variable
\item Try to make threads process data in parallel
\end{itemize}
\end{exerciseWithShortcut}
\end{frame}