STL (std) thread safety issues

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Philip V Pham

    STL (std) thread safety issues

    These questions apply to std vector, map, and cout:

    I am uncertain of the thread safety for reading/writing
    for std templates. I know if all threads are reading
    concurrently, it is thread safe. However, I have this situation:

    Case 1: map

    thread 1
    ---------
    someMapOb [key] = value //inserting new pair

    thread 2
    ---------

    interator pos;

    while (1==1)
    {
    for (pos = someMapOb.begin (); pos != someMapOb.end() , pos++ )
    {
    someValueOb = pos->second;

    someValueOb.foo ();

    }

    sleep (1)
    {


    Is safe for case 1 if I do that? I don't care
    if I miss a new inserted object in thread 2.
    If a new object inserted into the map, will the
    iterator be invalidated?
    The reason that I omit a mutex is to maximize performance.

    ---------------
    Case 2: queue

    thread 1
    --------
    someQueue.push ( value );

    thread 2
    ---------
    while ( ! someQueue.isEmp ty ()
    {
    // display a status indicator
    // NOte, I don't pop or push the Q here
    }


    Is safe to call isEmpty() while the Q is being
    pushed?

    --------------------------

    Case 3: cout

    thread 1
    --------
    cout << "Thank you in advance for your help!" << endl;

    thread 2
    ---------
    cout << "Display....dis play ....." << endl;

    I know the screen output might be messed up,
    but would this concurrent cout cause a buffer overfloat
    crash?

    Thank you vey much for your help!
    I look forward to hear from your solutions.




  • Pete C.

    #2
    Re: STL (std) thread safety issues

    Philip V Pham wrote:[color=blue]
    > These questions apply to std vector, map, and cout:
    >
    > I am uncertain of the thread safety for reading/writing
    > for std templates. I know if all threads are reading
    > concurrently, it is thread safe. However, I have this situation:
    >[/color]
    <snip>

    Please don't multipost. If you must post in multiple groups, crosspost.
    Standard C++ does not support threading, so your question is off topic for
    this group. Please ask in a group for your implementation.

    - Pete


    Comment

    • Dave Townsend

      #3
      Re: STL (std) thread safety issues

      STL has no built in thread support, so you'll have to extend the STL
      code with your own synchronization mechanisms to use STL in
      a multithreaded environment. Case1 and Case2 are clearly
      unsafe in my opinion. One of the troubles with thread programming
      is things can appear to work correctly in development, but strange
      bugs appear in the field when the execution environment can vary .
      You need to apply very strict logical reasoning
      in thread programming and be very conservative in your assumptions.
      After that, test your code on a multiprocessor machine.


      Case 1 - this is not thread safe, thread 1 may be preempted
      while performing the insertion, leaving the map in an undefined state,
      iteration over the map would be undefined. Inserting an element into
      a map rearranges the internal arrangement of elements, so if this is
      preempted
      the internal arrangement may not be in a valid state.

      You might want to look at the double-locking pattern which provides
      a more efficient mechanism to deal with locking shared data structures.
      Basically, a flag is set/reset to indicate a lock mutex lock is in place, if
      the flag is set, then thread gives up and try again later, otherwise the
      thread
      proceeds to acquire the lock and set the flag. This attempts to avoid the
      costly
      operation of trying to acquire the lock and failing.

      I'd have to look it up, but I think the map iterators would not be
      invalidated, that
      is an iterator would still "point" to the same element after an insertion,
      just
      that the internal links to its neighbours could be different, - again, if
      the rearrangment
      of the elements is preempted, imagine what chaos will result if you try to
      iterate
      over the elements...!


      case 2 - again, this is unlikely to work, the push operation is non-atomic
      so could be preempted mid-way, so you might have a situation where an
      element has been inserted intot the queue but the count of elements hasn't
      been updated...I in your example this is "harmless"situa tion, but I don't
      think I'd like
      to have it in my fly-by-wire navigation system


      case 3 - I don't know - cout could be implemented to serialize the two
      calls, but might not be for performance reasons with different
      implementations .

      dave

      "Philip V Pham" <pvanpham@yahoo .com> wrote in message
      news:EgGyc.1489 $Ff2.1127@newss vr16.news.prodi gy.com...[color=blue]
      > These questions apply to std vector, map, and cout:
      >
      > I am uncertain of the thread safety for reading/writing
      > for std templates. I know if all threads are reading
      > concurrently, it is thread safe. However, I have this situation:
      >
      > Case 1: map
      >
      > thread 1
      > ---------
      > someMapOb [key] = value //inserting new pair
      >
      > thread 2
      > ---------
      >
      > interator pos;
      >
      > while (1==1)
      > {
      > for (pos = someMapOb.begin (); pos != someMapOb.end() , pos++ )
      > {
      > someValueOb = pos->second;
      >
      > someValueOb.foo ();
      >
      > }
      >
      > sleep (1)
      > {
      >
      >
      > Is safe for case 1 if I do that? I don't care
      > if I miss a new inserted object in thread 2.
      > If a new object inserted into the map, will the
      > iterator be invalidated?
      > The reason that I omit a mutex is to maximize performance.
      >
      > ---------------
      > Case 2: queue
      >
      > thread 1
      > --------
      > someQueue.push ( value );
      >
      > thread 2
      > ---------
      > while ( ! someQueue.isEmp ty ()
      > {
      > // display a status indicator
      > // NOte, I don't pop or push the Q here
      > }
      >
      >
      > Is safe to call isEmpty() while the Q is being
      > pushed?
      >
      > --------------------------
      >
      > Case 3: cout
      >
      > thread 1
      > --------
      > cout << "Thank you in advance for your help!" << endl;
      >
      > thread 2
      > ---------
      > cout << "Display....dis play ....." << endl;
      >
      > I know the screen output might be messed up,
      > but would this concurrent cout cause a buffer overfloat
      > crash?
      >
      > Thank you vey much for your help!
      > I look forward to hear from your solutions.
      >
      >
      >
      >[/color]


      Comment

      • Dietmar Kuehl

        #4
        Re: STL (std) thread safety issues

        "Dave Townsend" <datownsend@com cast.net> wrote:[color=blue]
        > STL has no built in thread support, so you'll have to extend the STL
        > code with your own synchronization mechanisms to use STL in
        > a multithreaded environment.[/color]

        It is correct that the c++ standard does not require any multi-threading
        capabilities. However, implementations for multi-threaded environments
        typically have some support for multi-threading. In general, it is safe
        to read data structures from multiple threads but changing a data
        structure is allowed only for a thread with exclusive access to the data
        structure. Note that you typically have to inject some form of
        synchronization device after writing a data structure (eg. a mutex release)
        even if you can guarantee that the data structure is not accessed from
        multiple threads due to timing constraints: especially on multi processor
        systems the modified data is not always visible to other processors until
        it is explicitly written back.
        [color=blue]
        > Case1 and Case2 are clearly unsafe in my opinion.[/color]

        All three cases are unsafe.
        [color=blue]
        > You might want to look at the double-locking pattern which provides
        > a more efficient mechanism to deal with locking shared data structures.[/color]

        Note that the double-[checked] locking pattern does not work: it is a nice
        idea but actually introduces hard to find multi-threading bugs - after all,
        you explicitly handle multi-threading. I'm not a multi-threading expert
        (unless you count the advice "Avoid using multi-threadings! Use other
        approaches, e.g. multi-processing, where viable" as expertise...) to
        describe the reasons sufficiently well myself, I have only read arguments
        which make sense and reflect my experience with uses of the double-checked
        locking pattern. You might want to look at discussions e.g. in
        comp.lang.c++.m oderated or google for a descriptions of the problems
        (<http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLo cking.html>
        may be applicable to some extend).
        [color=blue]
        > I'd have to look it up, but I think the map iterators would not be
        > invalidated, that is an iterator would still "point" to the same element
        > after an insertion, just that the internal links to its neighbours could
        > be different, - again, if the rearrangment of the elements is preempted,
        > imagine what chaos will result if you try to iterate over the
        > elements...![/color]

        On multi-processors choas results even if the rearrangement is not
        preempted: the changes are made to the processor's cache and it requires
        some form of multi-threading synchronization to make the changes appear
        for other processors. Typical processors for multi-processor machines often
        have special instructions to flush the cache and invalidate the
        corresponding cache sections of other caches. The user interface to these
        instructions differ between platforms but a mutex always does the trick.
        [color=blue]
        > case 3 - I don't know - cout could be implemented to serialize the two
        > calls, but might not be for performance reasons with different
        > implementations .[/color]

        It is very unlikely that this done: locking internal to a stream is simply
        the wrong abstraction level. You need to put locking around the stream. You
        might want to preformat the output into a thread-private string stream and
        then merely insert the resulting string at once into a thread protected
        'std::cout'. This has two positive effects: the output is not garbled and
        the time 'std::cout' is blocked is minimized.
        --
        <mailto:dietmar _kuehl@yahoo.co m> <http://www.dietmar-kuehl.de/>
        <http://www.contendix.c om> - Software Development & Consulting

        Comment

        Working...