Skip to content

Commit af26ece

Browse files
hageboecksponcebernhardmgruber
committed
Rework slides on condition_variable.
The slides needed a bit more explanations, so the producer/consumer example now got an extra slide with a bit more text. Furthermore, the entire section received some minor improvements. Co-authored-by: Sebastien Ponce <[email protected]> Co-authored-by: Bernhard Manfred Gruber <[email protected]>
1 parent 8866f56 commit af26ece

File tree

1 file changed

+39
-26
lines changed

1 file changed

+39
-26
lines changed

talk/concurrency/condition.tex

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
\begin{frame}[fragile]
44
\frametitlecpp[11]{Condition variables}
5-
\begin{block}{Communicating thread dependencies}
5+
\begin{block}{Communicating between threads}
66
\begin{itemize}
7-
\item \mintinline{cpp}{std::condition_variable} from \mintinline{cpp}{<condition_variable>} header
7+
\item Take the case where threads are waiting for other thread(s)
8+
\item \mintinline{cpp}{std::condition_variable}
9+
\begin{itemize}
10+
\item from \mintinline{cpp}{<condition_variable>} header
11+
\end{itemize}
812
\item Allows for a thread to sleep (= conserve CPU time) until a given condition is satisfied
913
\end{itemize}
1014
\end{block}
@@ -23,12 +27,14 @@
2327
\end{frame}
2428

2529
\begin{frame}[fragile]
26-
\frametitlecpp[17]{Using condition variables}
27-
\begin{block}{Producer side}
30+
\frametitlecpp[17]{Using condition variables: notify}
31+
\begin{block}{Producer side: providing data to waiting threads}
2832
\begin{itemize}
29-
\item Imagine multiple threads sharing data. Protect it with a mutex
30-
\item Use a condition variable to notify consumers
31-
\item Optimization: Don't hold lock while notifying (would block the waking threads)
33+
\item Protect data with a mutex, and use condition variable to notify consumers
34+
\item Optimal use: don't hold lock while notifying
35+
\begin{itemize}
36+
\item waiting threads would be blocked
37+
\end{itemize}
3238
\end{itemize}
3339
\end{block}
3440
\begin{exampleblock}{}
@@ -48,43 +54,51 @@
4854
\end{frame}
4955

5056
\begin{frame}[fragile]
57+
\frametitlecpp[11]{Using condition variables: wait}
58+
\vspace{-1.2\baselineskip}
5159
\begin{overprint}
5260
\onslide<1>
53-
\begin{block}{Consumer side I: Going into wait}
61+
\begin{block}{Mechanics of wait}
5462
\begin{itemize}
55-
\item Start many threads which have to wait for shared data
56-
\item Provide a lock to be managed by \mintinline{cpp}{wait}
57-
\item \mintinline{cpp}{wait} will only lock while necessary; unlocked while sleeping
58-
\item Threads might wake up, but \mintinline{cpp}{wait} returns only when condition satisfied
63+
\item Many threads are waiting for shared data
64+
\item Pass a \mintinline{cpp}{unique_lock} and a predicate for wakeup to \mintinline{cpp}{wait()}
65+
\item \mintinline{cpp}{wait()} sends threads to sleep while predicate is \mintinline{cpp}{false}
66+
\item \mintinline{cpp}{wait()} will only lock when necessary; unlocked while sleeping
67+
\item Threads might wake up spuriously, but \mintinline{cpp}{wait()} returns only when lock available \emph{and} predicate \mintinline{cpp}{true}
5968
\end{itemize}
6069
\end{block}
6170
\onslide<2->
62-
\begin{block}{Consumer side II: Waking up}
71+
\begin{block}{Waiting / waking up}
6372
\begin{itemize}
6473
\item \mintinline{cpp}{notify_all()} is called, threads wake up
65-
\item Threads try to acquire mutex, evaluate condition
66-
\item One thread succeeds to acquire mutex, exits from \mintinline{cpp}{wait}
67-
\item \alt<2>{ {\color{red} Problem}: Other threads still blocked!}{ {\color{green!80!black} Solution:} Put locking and waiting in a scope}
74+
\item Threads try to lock mutex, and evaluate predicate
75+
\item One thread succeeds to acquire mutex, starts data processing
76+
\item {\color{red} Problem}: Thread holds mutex now, other threads are blocked!
6877
\end{itemize}
6978
\end{block}
7079
\end{overprint}
7180

72-
\begin{exampleblock}{}
73-
\begin{overprint}
74-
\onslide<1-2>
75-
\begin{cppcode*}{gobble=2,highlightlines=4}
81+
\begin{alertblock}{Na\"ive waiting}
82+
\begin{cppcode*}{gobble=2,highlightlines=3}
7683
auto processData = [&](){
77-
7884
std::unique_lock<std::mutex> lock{mutex};
7985
cond.wait(lock, [&](){ return data.isReady(); });
80-
8186
process(data);
8287
};
83-
std::thread t1{processData}, t2{processData}, ...;
84-
for (auto t : {&producer, &t1, &t2, ...}) t->join();
8588
\end{cppcode*}
89+
\end{alertblock}
90+
\end{frame}
91+
92+
\begin{frame}[fragile]
93+
\frametitlecpp[11]{Using condition variables: correct wait}
94+
\begin{block}{Waiting / waking up}
95+
\begin{itemize}
96+
\item {\color{green!50!black} Solution:} Put locking and waiting in a scope
97+
\item Threads will one-by-one wake up, acquire lock, evaluate predicate, release lock
98+
\end{itemize}
99+
\end{block}
86100

87-
\onslide<3>
101+
\begin{exampleblock}{Correct waiting}
88102
\begin{cppcode*}{gobble=2}
89103
auto processData = [&](){
90104
{
@@ -96,7 +110,6 @@
96110
std::thread t1{processData}, t2{processData}, ...;
97111
for (auto t : {&producer, &t1, &t2, ...}) t->join();
98112
\end{cppcode*}
99-
\end{overprint}
100113
\end{exampleblock}
101114
\end{frame}
102115

0 commit comments

Comments
 (0)