[libstdc++] Notes on threading and I/O

Nathan Myers ncm@nospam.cantrip.org
Wed Oct 10 23:42:00 GMT 2001


This patch is not correct.  Details below...

On Thu, Oct 11, 2001 at 01:09:16AM -0500, Loren James Rittle wrote:
> In article < 20011010144700.A26789@disaster.jaj.com >,
> Phil Edwards <pedwards@disaster.jaj.com> writes:
> 
> >> It is better, IMHO, to state under which conditions the
> >> library is thread-safe than to ``just say no'':
> 
> > Can you go ahead and apply this patch?
> 
> OK, here is the patch I just applied to mainline.  I added examples to
> better display some points and improved my word choice.  I am still
> working on chapter 17 rewrite.
> 
> Phil, I don't have lynx installed so whenever you next regenerate
> docs/html/faq/index.txt you will get my changes as well (OK, at least
> I admit I'm bad).

[Lynx stinks.  Please use w3m for html->text conversions.]
 
> 2001-10-11  Loren J. Rittle  <ljrittle@acm.org>
> 
>         * docs/html/faq/index.html (Is libstdc++-v3 thread-safe?): Rewrite.
>         * docs/html/23_containers/howto.html (Containers and multithreading):
>         Update.
> 
> Index: docs/html/faq/index.html
> ===================================================================
> RCS file: /cvs/gcc/egcs/libstdc++-v3/docs/html/faq/index.html,v
> retrieving revision 1.19
> diff -c -r1.19 index.html
> *** index.html	2001/10/09 22:23:52	1.19
> --- index.html	2001/10/11 05:57:05
> ***************
> *** 686,704 ****
>   
>   <hr>
>      <h2><a name="5_6">5.6 Is libstdc++-v3 thread-safe?</a></h2>
> !       <p>Quick answer:  no, as of 3.0, most of the library is not
> !          safe for multithreaded access.  The string class is MT-safe.
>         </p>
> !       <p>This is assuming that your idea of "multithreaded"
> !          is the same as ours...  The general question of multithreading
> !          and libstdc++-v3 is addressed in the chapter-specific advice for
> !          <a href="../17_intro/howto.html#3">Library Introduction</a>.
> !          Threadsafe containers are covered in more detail in
> !          <a href="../23_containers/howto.html">the Received Wisdom section
> !          on containers</a>.  Threading and I/O are discussed in
> !          <a href="../27_io/howto.html">the I/O chapter</a>.
> !          <!-- I have successfully evaded the topic; my work here is
> !               done- no, wait, I have to write those other sections... -->
>         </p>
>   
>   <hr>
> --- 686,743 ----
>   
>   <hr>
>      <h2><a name="5_6">5.6 Is libstdc++-v3 thread-safe?</a></h2>
> !       <p>When the system's libc is itself thread-safe, libstdc++-v3
> !          strives to be thread-safe.  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
> !          into great detail, here is an example which requires
> !          user-level locks:
>         </p>
> !          <pre>
> !        library_class_a shared_object_a;
> ! 
> !        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
> !        }
> ! 
> !        // Multiple copies of thread_main() are started in independent threads.
> !          </pre>
> !       <p>Under the assumption that object_a and object_b are never
> !          exposed to another thread, here is an example that should not
> !          require any user-level locks:
> !       </p>
> !          <pre>
> !        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 ();
> !        }
> !          </pre>
> !       <p>However, as of gcc 3.0 and point releases, beware that there
> !          may be cases where shared nested or global objects (neither
> !          of which are visible to user-code) are affected or used
> !          without any internal locking.
> ! 	 <!-- Is this warning still required? - Loren -->

This warning is not correct, AFAIK.  It is worth noting, instead, that 
some architectures (HPPA?) don't have the necessary support for thread 
safety.

> !       </p>
> !       <p>In some cases, a stronger thread-safe claim is made.  The
> ! 	 string class is thread-safe without user-code guards (i.e. a
> ! 	 string object may be shared and accessed between threads
> ! 	 without user-level locking).  

The above statement is completely false.  There is no such string
implementation in the library.  std::basic_string<> observes 
precisely the same kind of thread safety as other library objects.
(It has to work a bit harder to get there because of its internal
sharing.)

> ... The IO classes are thread-safe
> ! 	 with user-code guards whenever the same user-visible object
> ! 	 may be accessed by multiple threads.  The container classes
> ! 	 are thread-safe with user-code guards whenever the same
> ! 	 container may be accessed by multiple threads.  

I'm not sure I understand the above correctly; it's just stated 
awkwardly enough to encourage misunderstanding.  I might propose:

  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.  This
  requirement includes both read and write access to objects; do
  not assume that two threads may read a shared standard container
  at the same time.

> All accesses
> ! 	 to hidden shared objects (e.g. the global allocator objects)
> ! 	 are believed to be properly guarded within the library.
> !       </p>
> !       <p>See chapters <a href="../17_intro/howto.html#3">17</a>,
> !          <a href="../23_containers/howto.html#3">23</a> and
> ! 	 <a href="../27_io/howto.html#9">27</a> for more information.
>         </p>
>   
>   <hr>
> Index: docs/html/23_containers/howto.html
> ===================================================================
> RCS file: /cvs/gcc/egcs/libstdc++-v3/docs/html/23_containers/howto.html,v
> retrieving revision 1.14
> diff -c -r1.14 howto.html
> *** howto.html	2001/10/09 20:18:09	1.14
> --- howto.html	2001/10/11 05:57:05
> ***************
> *** 192,259 ****
>   
>   <hr>
>   <h2><a name="3">Containers and multithreading</a></h2>
> !    <p>This section will mention some of the problems in designing MT
> !       programs that use Standard containers.  For information on other
> !       aspects of multithreading (e.g., the library as a whole), see
> !       the Received Wisdom on Chapter 17.  This section only applies
> !       when gcc and libstdc++-v3 were configured with --enable-threads.
> !    </p>
> !    <p>Two excellent pages to read when working with templatized containers
> !       and threads are
>         <a href=" http://www.sgi.com/tech/stl/thread_safety.html" ;>SGI's
>         http://www.sgi.com/tech/stl/thread_safety.html </a> and
>         <a href=" http://www.sgi.com/tech/stl/Allocators.html" ;>SGI's
> !       http://www.sgi.com/tech/stl/Allocators.html </a>.  The
> !       libstdc++-v3 uses the same definition of thread safety
> !       when discussing design.  A key point that beginners may miss is the
>         fourth major paragraph of the first page mentioned above
> !       ("For most clients,"...), pointing
> !       out that locking must nearly always be done outside the container,
> !       by client code (that'd be you, not us *grin*).
> !       <em>However, please take caution when considering the discussion
> !       about the user-level configuration of the mutex lock
> !       implementation inside the STL container-memory allocator on that
> !       page.  For the sake of this discussion, libstdc++-v3 configures
> !       the SGI STL implementation, not you.  We attempt to configure
> !       the mutex lock as is best for your platform.  In particular,
> !       past advice was for people using g++ to explicitly define
> !       _PTHREADS on the command line to get a thread-safe STL.  This
> !       is no longer required for your port.  It may or may not be
> !       a good idea for your port.  Extremely big caution: if you
> !       compile some of your application code against the STL with one
> !       set of threading flags and macros and another portion of the
> !       code with different flags and macros that influence the
> !       selection of the mutex lock, you may well end up with multiple
> !       locking mechanisms in use which don't impact each other in the
> !       manner that they should.  Everything might link and all code
> !       might have been built with a perfectly reasonable thread model
> !       but you may have two internal ABIs in play within the
> !       application.  This might produce races, memory leaks and fatal
> !       crashes.  In any multithreaded application using STL, this
> !       is the first thing to study well before blaming the allocator.</em>
> !    </p>
> !    <p>You didn't read it, did you?  *sigh*  I'm serious, go read the
> !       SGI page.  It's really good and doesn't take long, and makes most
> !       of the points that would otherwise have to be made here (and does
> !       a better job).
> !    </p>
> !    <p>That's much better.  Now, the issue of MT has been brought up on
> !       the libstdc++-v3 mailing list as well as the main GCC mailing list
> !       several times.  The Chapter 17 HOWTO has some links into the mail
> !       archives, so you can see what's been thrown around.  The usual
> !       container (or pseudo-container, depending on how you look at it)
> !       that people have in mind is <code>string</code>, which is one of the
> !       points where libstdc++ departs from the SGI STL.  As of the
> !       2.90.8 snapshot, the libstdc++-v3 string class is safe for
> !       certain kinds of multithreaded access.
> !    </p>
>      <p>For implementing a container which does its own locking, it is
> !       trivial to (as SGI suggests) provide a wrapper class which obtains
> !       the lock, performs the container operation, then releases the lock.
> !       This could be templatized <em>to a certain extent</em>, on the
> !       underlying container and/or a locking mechanism.  Trying to provide
> !       a catch-all general template solution would probably be more trouble
> !       than it's worth.
>      </p>
>      <p>Return <a href="#top">to top of page</a> or
>         <a href="../faq/index.html">to the FAQ</a>.
> --- 192,246 ----
>   
>   <hr>
>   <h2><a name="3">Containers and multithreading</a></h2>
> !    <p>This section discusses issues surrounding the design of
> !       multithreaded applications which use Standard C++ containers.
> !       All information in this section is current as of the gcc 3.0
> !       release and all later point releases.  Although earlier gcc
> !       releases had a different approach to threading configuration and
> !       proper compilation, the basic code design rules presented here
> !       were similar.  For information on all other aspects of
> !       multithreading as it relates to libstdc++, including details on
> !       the proper compilation of threaded code (and compatibility between
> !       threaded and non-threaded code), see Chapter 17.
> !   </p>
> !    <p>Two excellent pages to read when working with the Standard C++
> !       containers and threads are
>         <a href=" http://www.sgi.com/tech/stl/thread_safety.html" ;>SGI's
>         http://www.sgi.com/tech/stl/thread_safety.html </a> and
>         <a href=" http://www.sgi.com/tech/stl/Allocators.html" ;>SGI's
> !       http://www.sgi.com/tech/stl/Allocators.html </a>.
> !   </p>
> !    <p><em>However, please ignore all discussions about the user-level
> !       configuration of the lock implementation inside the STL
> !       container-memory allocator on those pages.  For the sake of this
> !       discussion, libstdc++-v3 configures the SGI STL implementation,
> !       not you.  This is quite different from how gcc pre-3.0 worked.
> !       In particular, past advice was for people using g++ to
> !       explicitly define _PTHREADS or other macros or port-specific
> !       compilation options on the command line to get a thread-safe
> !       STL.  This is no longer required for any port and should no
> !       longer be done unless you really know what you are doing and
> !       assume all responsibility.</em>
> !   </p>
> !    <p>Since the container implementation of libstdc++-v3 uses the SGI
> !       code, we use the same definition of thread safety as SGI when
> !       discussing design.  A key point that beginners may miss is the
>         fourth major paragraph of the first page mentioned above
> !       ("For most clients,"...), which points out that
> !       locking must nearly always be done outside the container, by
> !       client code (that'd be you, not us).  There is a notable
> !       exceptions to this rule.  Allocators called while a container or
> !       element is constructed uses an internal lock obtained and
> !       released solely within libstdc++-v3 code (in fact, this is the
> !       reason STL requires any knowledge of the thread configuration).
> !   </p>
>      <p>For implementing a container which does its own locking, it is
> !       trivial to provide a wrapper class which obtains the lock (as
> !       SGI suggests), performs the container operation, and then
> !       releases the lock.  This could be templatized <em>to a certain
> !       extent</em>, on the underlying container and/or a locking
> !       mechanism.  Trying to provide a catch-all general template
> !       solution would probably be more trouble than it's worth.
>      </p>
>      <p>Return <a href="#top">to top of page</a> or
>         <a href="../faq/index.html">to the FAQ</a>.



More information about the Libstdc++ mailing list