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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
|
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0"
xml:id="manual.ext.concurrency" xreflabel="Concurrency Extensions">
<?dbhtml filename="ext_concurrency.html"?>
<info><title>Concurrency</title>
<keywordset>
<keyword>
ISO C++
</keyword>
<keyword>
library
</keyword>
</keywordset>
</info>
<section xml:id="manual.ext.concurrency.design" xreflabel="Design"><info><title>Design</title></info>
<section xml:id="manual.ext.concurrency.design.threads" xreflabel="Threads API"><info><title>Interface to Locks and Mutexes</title></info>
<para>The file <ext/concurrence.h> contains all the higher-level
constructs for playing with threads. In contrast to the atomics layer,
the concurrence layer consists largely of types. All types are defined within <code>namespace __gnu_cxx</code>.
</para>
<para>
These types can be used in a portable manner, regardless of the
specific environment. They are carefully designed to provide optimum
efficiency and speed, abstracting out underlying thread calls and
accesses when compiling for single-threaded situations (even on hosts
that support multiple threads.)
</para>
<para>The enumerated type <code>_Lock_policy</code> details the set of
available locking
policies: <code>_S_single</code>, <code>_S_mutex</code>,
and <code>_S_atomic</code>.
</para>
<itemizedlist>
<listitem><para><code>_S_single</code></para>
<para>Indicates single-threaded code that does not need locking.
</para>
</listitem>
<listitem><para><code>_S_mutex</code></para>
<para>Indicates multi-threaded code using thread-layer abstractions.
</para>
</listitem>
<listitem><para><code>_S_atomic</code></para>
<para>Indicates multi-threaded code using atomic operations.
</para>
</listitem>
</itemizedlist>
<para>The compile-time constant <code>__default_lock_policy</code> is set
to one of the three values above, depending on characteristics of the
host environment and the current compilation flags.
</para>
<para>Two more datatypes make up the rest of the
interface: <code>__mutex</code>, and <code>__scoped_lock</code>.
</para>
<para>
</para>
<para>The scoped lock idiom is well-discussed within the C++
community. This version takes a <code>__mutex</code> reference, and
locks it during construction of <code>__scoped_locke</code> and
unlocks it during destruction. This is an efficient way of locking
critical sections, while retaining exception-safety.
</para>
</section>
<section xml:id="manual.ext.concurrency.design.atomics" xreflabel="Atomic API"><info><title>Interface to Atomic Functions</title></info>
<para>
Two functions and one type form the base of atomic support.
</para>
<para>The type <code>_Atomic_word</code> is a signed integral type
supporting atomic operations.
</para>
<para>
The two functions functions are:
</para>
<programlisting>
_Atomic_word
__exchange_and_add_dispatch(volatile _Atomic_word*, int);
void
__atomic_add_dispatch(volatile _Atomic_word*, int);
</programlisting>
<para>Both of these functions are declared in the header file
<ext/atomicity.h>, and are in <code>namespace __gnu_cxx</code>.
</para>
<itemizedlist>
<listitem><para>
<code>
__exchange_and_add_dispatch
</code>
</para>
<para>Adds the second argument's value to the first argument. Returns the old value.
</para>
</listitem>
<listitem><para>
<code>
__atomic_add_dispatch
</code>
</para>
<para>Adds the second argument's value to the first argument. Has no return value.
</para>
</listitem>
</itemizedlist>
<para>
These functions forward to one of several specialized helper
functions, depending on the circumstances. For instance,
</para>
<para>
<code>
__exchange_and_add_dispatch
</code>
</para>
<para>
Calls through to either of:
</para>
<itemizedlist>
<listitem><para><code>__exchange_and_add</code>
</para>
<para>Multi-thread version. Inlined if compiler-generated builtin atomics
can be used, otherwise resolved at link time to a non-builtin code
sequence.
</para>
</listitem>
<listitem><para><code>__exchange_and_add_single</code>
</para>
<para>Single threaded version. Inlined.</para>
</listitem>
</itemizedlist>
<para>However, only <code>__exchange_and_add_dispatch</code>
and <code>__atomic_add_dispatch</code> should be used. These functions
can be used in a portable manner, regardless of the specific
environment. They are carefully designed to provide optimum efficiency
and speed, abstracting out atomic accesses when they are not required
(even on hosts that support compiler intrinsics for atomic
operations.)
</para>
<para>
In addition, there are two macros
</para>
<para>
<code>
_GLIBCXX_READ_MEM_BARRIER
</code>
</para>
<para>
<code>
_GLIBCXX_WRITE_MEM_BARRIER
</code>
</para>
<para>
Which expand to the appropriate write and read barrier required by the
host hardware and operating system.
</para>
</section>
</section>
<section xml:id="manual.ext.concurrency.impl" xreflabel="Implementation"><info><title>Implementation</title></info>
<section xml:id="manual.ext.concurrency.impl.atomic_fallbacks" xreflabel="Atomic F"><info><title>Using Builtin Atomic Functions</title></info>
<para>The functions for atomic operations described above are either
implemented via compiler intrinsics (if the underlying host is
capable) or by library fallbacks.</para>
<para>Compiler intrinsics (builtins) are always preferred. However, as
the compiler builtins for atomics are not universally implemented,
using them directly is problematic, and can result in undefined
function calls. (An example of an undefined symbol from the use
of <code>__sync_fetch_and_add</code> on an unsupported host is a
missing reference to <code>__sync_fetch_and_add_4</code>.)
</para>
<para>In addition, on some hosts the compiler intrinsics are enabled
conditionally, via the <code>-march</code> command line flag. This makes
usage vary depending on the target hardware and the flags used during
compile.
</para>
<para>
If builtins are possible for bool-sized integral types,
<code>_GLIBCXX_ATOMIC_BUILTINS_1</code> will be defined.
If builtins are possible for int-sized integral types,
<code>_GLIBCXX_ATOMIC_BUILTINS_4</code> will be defined.
</para>
<para>For the following hosts, intrinsics are enabled by default.
</para>
<itemizedlist>
<listitem><para>alpha</para></listitem>
<listitem><para>ia64</para></listitem>
<listitem><para>powerpc</para></listitem>
<listitem><para>s390</para></listitem>
</itemizedlist>
<para>For others, some form of <code>-march</code> may work. On
non-ancient x86 hardware, <code>-march=native</code> usually does the
trick.</para>
<para> For hosts without compiler intrinsics, but with capable
hardware, hand-crafted assembly is selected. This is the case for the following hosts:
</para>
<itemizedlist>
<listitem><para>cris</para></listitem>
<listitem><para>hppa</para></listitem>
<listitem><para>i386</para></listitem>
<listitem><para>i486</para></listitem>
<listitem><para>m48k</para></listitem>
<listitem><para>mips</para></listitem>
<listitem><para>sparc</para></listitem>
</itemizedlist>
<para>And for the rest, a simulated atomic lock via pthreads.
</para>
<para> Detailed information about compiler intrinsics for atomic operations can be found in the GCC <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html"> documentation</link>.
</para>
<para> More details on the library fallbacks from the porting <link linkend="internals.thread_safety">section</link>.
</para>
</section>
<section xml:id="manual.ext.concurrency.impl.thread" xreflabel="Pthread"><info><title>Thread Abstraction</title></info>
<para>A thin layer above IEEE 1003.1 (i.e. pthreads) is used to abstract
the thread interface for GCC. This layer is called "gthread," and is
comprised of one header file that wraps the host's default thread layer with
a POSIX-like interface.
</para>
<para> The file <gthr-default.h> points to the deduced wrapper for
the current host. In libstdc++ implementation files,
<bits/gthr.h> is used to select the proper gthreads file.
</para>
<para>Within libstdc++ sources, all calls to underlying thread functionality
use this layer. More detail as to the specific interface can be found in the source <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a00883_source.html">documentation</link>.
</para>
<para>By design, the gthread layer is interoperable with the types,
functions, and usage found in the usual <pthread.h> file,
including <code>pthread_t</code>, <code>pthread_once_t</code>, <code>pthread_create</code>,
etc.
</para>
</section>
</section>
<section xml:id="manual.ext.concurrency.use" xreflabel="Use"><info><title>Use</title></info>
<para>Typical usage of the last two constructs is demonstrated as follows:
</para>
<programlisting>
#include <ext/concurrence.h>
namespace
{
__gnu_cxx::__mutex safe_base_mutex;
} // anonymous namespace
namespace other
{
void
foo()
{
__gnu_cxx::__scoped_lock sentry(safe_base_mutex);
for (int i = 0; i < max; ++i)
{
_Safe_iterator_base* __old = __iter;
__iter = __iter-<_M_next;
__old-<_M_detach_single();
}
}
</programlisting>
<para>In this sample code, an anonymous namespace is used to keep
the <code>__mutex</code> private to the compilation unit,
and <code>__scoped_lock</code> is used to guard access to the critical
section within the for loop, locking the mutex on creation and freeing
the mutex as control moves out of this block.
</para>
<para>Several exception classes are used to keep track of
concurrence-related errors. These classes
are: <code>__concurrence_lock_error</code>, <code>__concurrence_unlock_error</code>, <code>__concurrence_wait_error</code>,
and <code>__concurrence_broadcast_error</code>.
</para>
</section>
</chapter>
|