re PR libstdc++/50834 (Documentation about STL thread safety is ambiguous)
PR libstdc++/50834 * doc/xml/manual/using.xml: Update thread safety docs w.r.t. C++11. From-SVN: r180359
This commit is contained in:
parent
a0d90b97f0
commit
ec8ab7c4e4
2 changed files with 95 additions and 16 deletions
|
@ -1,3 +1,8 @@
|
|||
2011-10-22 Jonathan Wakely <jwakely.gcc@gmail.com>
|
||||
|
||||
PR libstdc++/50834
|
||||
* doc/xml/manual/using.xml: Update thread safety docs w.r.t. C++11.
|
||||
|
||||
2011-10-22 Jonathan Wakely <jwakely.gcc@gmail.com>
|
||||
|
||||
PR libstdc++/50196
|
||||
|
|
|
@ -1281,9 +1281,16 @@ A quick read of the relevant part of the GCC
|
|||
<section xml:id="manual.intro.using.concurrency.thread_safety" xreflabel="Thread Safety"><info><title>Thread Safety</title></info>
|
||||
|
||||
|
||||
|
||||
<para>
|
||||
We currently use the <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.sgi.com/tech/stl/thread_safety.html">SGI STL</link> definition of thread safety.
|
||||
In the terms of the 2011 C++ standard a thread-safe program is one which
|
||||
does not perform any conflicting non-atomic operations on memory locations
|
||||
and so does not contain any data races.
|
||||
The standard places requirements on the library to ensure that no data
|
||||
races are caused by the library itself or by programs which use the
|
||||
library correctly (as described below).
|
||||
The C++11 memory model and library requirements are a more formal version
|
||||
of the <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.sgi.com/tech/stl/thread_safety.html">SGI STL</link> definition of thread safety, which the library used
|
||||
prior to the 2011 standard.
|
||||
</para>
|
||||
|
||||
|
||||
|
@ -1329,17 +1336,25 @@ gcc version 4.1.2 20070925 (Red Hat 4.1.2-33)
|
|||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
<para>The user-code must guard against concurrent method calls which may
|
||||
access any particular library object's state. Typically, the
|
||||
application programmer may infer what object locks must be held
|
||||
based on the objects referenced in a method call. Without getting
|
||||
|
||||
<para>The user code must guard against concurrent function calls which
|
||||
access any particular library object's state when one or more of
|
||||
those accesses modifies the state. An object will be modified by
|
||||
invoking a non-const member function on it or passing it as a
|
||||
non-const argument to a library function. An object will not be
|
||||
modified by invoking a const member function on it or passing it to
|
||||
a function as a pointer- or reference-to-const.
|
||||
Typically, the application
|
||||
programmer may infer what object locks must be held based on the
|
||||
objects referenced in a function call and whether the objects are
|
||||
accessed as const or non-const. Without getting
|
||||
into great detail, here is an example which requires user-level
|
||||
locks:
|
||||
</para>
|
||||
<programlisting>
|
||||
library_class_a shared_object_a;
|
||||
|
||||
thread_main () {
|
||||
void thread_main () {
|
||||
library_class_b *object_b = new library_class_b;
|
||||
shared_object_a.add_b (object_b); // must hold lock for shared_object_a
|
||||
shared_object_a.mutate (); // must hold lock for shared_object_a
|
||||
|
@ -1347,25 +1362,84 @@ gcc version 4.1.2 20070925 (Red Hat 4.1.2-33)
|
|||
|
||||
// Multiple copies of thread_main() are started in independent threads.</programlisting>
|
||||
<para>Under the assumption that object_a and object_b are never exposed to
|
||||
another thread, here is an example that should not require any
|
||||
another thread, here is an example that does not require any
|
||||
user-level locks:
|
||||
</para>
|
||||
<programlisting>
|
||||
thread_main () {
|
||||
void thread_main () {
|
||||
library_class_a object_a;
|
||||
library_class_b *object_b = new library_class_b;
|
||||
object_a.add_b (object_b);
|
||||
object_a.mutate ();
|
||||
} </programlisting>
|
||||
<para>All library objects are safe to use in a multithreaded program as
|
||||
long as each thread carefully locks out access by any other
|
||||
thread while it uses any object visible to another thread, i.e.,
|
||||
treat library objects like any other shared resource. In general,
|
||||
this requirement includes both read and write access to objects;
|
||||
unless otherwise documented as safe, do not assume that two threads
|
||||
may access a shared standard library object at the same time.
|
||||
|
||||
<para>All library types are safe to use in a multithreaded program
|
||||
if objects are not shared between threads or as
|
||||
long each thread carefully locks out access by any other
|
||||
thread while it modifies any object visible to another thread.
|
||||
Unless otherwise documented, the only exceptions to these rules
|
||||
are atomic operations on the types in
|
||||
<filename class="headerfile"><atomic></filename>
|
||||
and lock/unlock operations on the standard mutex types in
|
||||
<filename class="headerfile"><mutex></filename>. These
|
||||
atomic operations allow concurrent accesses to the same object
|
||||
without introducing data races.
|
||||
</para>
|
||||
|
||||
<para>The following member functions of standard containers can be
|
||||
considered to be const for the purposes of avoiding data races:
|
||||
<code>begin</code>, <code>end</code>, <code>rbegin</code>, <code>rend</code>,
|
||||
<code>front</code>, <code>back</code>, <code>data</code>,
|
||||
<code>find</code>, <code>lower_bound</code>, <code>upper_bound</code>,
|
||||
<code>equal_range</code>, <code>at</code>
|
||||
and, except in associative or unordered associative containers,
|
||||
<code>operator[]</code>. In other words, although they are non-const
|
||||
so that they can return mutable iterators, those member functions
|
||||
will not modify the container.
|
||||
Accessing an iterator might cause a non-modifying access to
|
||||
the container the iterator refers to (for example incrementing a
|
||||
list iterator must access the pointers between nodes, which are part
|
||||
of the container and so conflict with other accesses to the container).
|
||||
</para>
|
||||
|
||||
<para>Programs which follow the rules above will not encounter data
|
||||
races in library code, even when using library types which share
|
||||
state between distinct objects. In the example below the
|
||||
<code>shared_ptr</code> objects share a reference count, but
|
||||
because the code does not perform any non-const operations on the
|
||||
globally-visible object, the library ensures that the reference
|
||||
count updates are atomic and do not introduce data races:
|
||||
</para>
|
||||
<programlisting>
|
||||
std::shared_ptr<int> global_sp;
|
||||
|
||||
void thread_main() {
|
||||
auto local_sp = global_sp; // OK, copy constructor's parameter is reference-to-const
|
||||
|
||||
int i = *global_sp; // OK, operator* is const
|
||||
int j = *local_sp; // OK, does not operate on global_sp
|
||||
|
||||
// *global_sp = 2; // NOT OK, modifies int visible to other threads
|
||||
// *local_sp = 2; // NOT OK, modifies int visible to other threads
|
||||
|
||||
// global_sp.reset(); // NOT OK, reset is non-const
|
||||
local_sp.reset(); // OK, does not operate on global_sp
|
||||
}
|
||||
|
||||
int main() {
|
||||
global_sp.reset(new int(1));
|
||||
std::thread t1(thread_main);
|
||||
std::thread t2(thread_main);
|
||||
t1.join();
|
||||
t2.join();
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
<para>For further details of the C++11 memory model see Hans-J. Boehm's
|
||||
<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/user-faq.html">Threads
|
||||
and memory model for C++</link> pages, particularly the <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/threadsintro.html">introduction</link>
|
||||
and <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/user-faq.html">FAQ</link>.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
<section xml:id="manual.intro.using.concurrency.atomics" xreflabel="Atomics"><info><title>Atomics</title></info>
|
||||
|
|
Loading…
Add table
Reference in a new issue