forked from hsf-training/cpluspluscourse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatomic.tex
126 lines (121 loc) · 4.04 KB
/
atomic.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
\subsection[atomic]{Atomic types}
\begin{frame}[fragile]
\frametitlecpp[11]{Atomic types in \cpp}
\begin{block}{\texttt{std::atomic} template}
\begin{itemize}
\item Any trivially copyable type can be made atomic in C++
\item Most useful for integral types
\item May internally use locks for custom types
\end{itemize}
\end{block}
\begin{exampleblock}{}
\begin{cppcode*}{}
std::atomic<int> a{0};
std::thread t1([&](){ a++; });
std::thread t2([&](){ a++; });
a += 2;
t1.join(); t2.join();
assert( a == 4 ); // Guaranteed to succeed
\end{cppcode*}
\end{exampleblock}
\end{frame}
\begin{frame}[fragile]
\begin{alertblock}{Warning: Expressions using an atomic type are \textit{not} atomic!}
\begin{cppcode*}{}
std::atomic<int> a{0};
std::thread t1([&]{ a = a + 2; });
std::thread t2([&]{ a = a + 2; });
\end{cppcode*}
\begin{itemize}
\item Atomic load; value+2; atomic store
\end{itemize}
\end{alertblock}
\begin{block}{Sequence diagram}
\begin{tikzpicture}
\begin{umlseqdiag}
\umlobject[x=0]{Thread 1}
\umlobject[x=3, fill=blue!20]{atomic}
\umlobject[x=6]{Thread 2}
\begin{umlcall}[op=load]{Thread 1}{atomic}
\end{umlcall}
\begin{umlcall}[op=+2]{Thread 1}{Thread 1}
\end{umlcall}
\begin{umlcall}[op=load]{Thread 2}{atomic}
\end{umlcall}
\begin{umlcall}[op=+2]{Thread 2}{Thread 2}
\end{umlcall}
\begin{umlcall}[op=store 2]{Thread 1}{atomic}
\end{umlcall}
\begin{umlcall}[op=store 2]{Thread 2}{atomic}
\end{umlcall}
\end{umlseqdiag}
\draw[-triangle 60](9,0) -- (9,-4) node[right, pos=0.5]{time};
\end{tikzpicture}
\end{block}
\end{frame}
\begin{frame}[fragile]
\begin{block}{Solution: Use atomic member functions}
\begin{itemize}
\item The member functions of \cppinline{std::atomic} are thread safe
\item \cppinline{fetch_add} and \cppinline{operator+=}: atomic \{ load; add; store \}
\item But don't confuse ``\cppinline{a += 2}'' and ``\cppinline{a = a + 2}''
\end{itemize}
\end{block}
\begin{exampleblock}{}
\begin{cppcode*}{}
std::atomic<int> a{0};
std::thread t1([&]{ a.fetch_add(2); });
std::thread t2([&]{ a += 2; });
\end{cppcode*}
\end{exampleblock}
\begin{block}{Sequence diagram}
\begin{tikzpicture}
\begin{umlseqdiag}
\umlobject[x=0]{Thread 1}
\umlobject[x=3, fill=blue!20]{atomic}
\umlobject[x=6]{Thread 2}
\begin{umlcall}[op=fetch\_add]{Thread 1}{atomic}
\end{umlcall}
\begin{umlcall}[op=\texttt{+=}, dt=9]{Thread 2}{atomic}
\end{umlcall}
\end{umlseqdiag}
\draw[-triangle 60](9,0) -- (9,-2) node[right, pos=0.5]{time};
\end{tikzpicture}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitlecpp[20]{Atomic references}
\begin{block}{\texttt{std::atomic\_ref} template}
\begin{itemize}
\item Wraps a \cppinline{T&} and makes access to it atomic
\item Like \cppinline{std::atomic<T>}, but does not contain the \cppinline{T}
\end{itemize}
\end{block}
\begin{exampleblock}{}
\begin{cppcode*}{}
int a{0};
std::thread t1([&]{ std::atomic_ref<int> r{a}; r++;});
std::thread t2([&]{ std::atomic_ref{a}++; });
t1.join(); t2.join();
a += 2; // non-atomic (fine, threads joined before)
assert( a == 4 ); // Guaranteed to succeed
\end{cppcode*}
\end{exampleblock}
\begin{alertblock}{Don't mix concurrent atomic and non-atomic access}
\begin{cppcode*}{}
std::thread t3([&]{ std::atomic_ref{a}++; });
a += 2; // data race
t3.join();
\end{cppcode*}
\end{alertblock}
\end{frame}
\begin{frame}[fragile]
\frametitle{Atomic types in \cpp}
\begin{exercise}{Atomics}
\begin{itemize}
\item Go to \texttt{exercises/atomic}
\item You'll find a program with the same race condition as in \texttt{race}
\item Fix it using \cppinline{std::atomic}
\end{itemize}
\end{exercise}
\end{frame}