none
Can STL streams run concurrently ?

    Question

  • Hello,

     

    (This is my first post on MSDN, so please feel free to move this post to a more appropriate place).

     

    Working on parallelizing my application I have come across with the issue that STL streams cannot be effectively used concurrently. This conclusion sounds too strong for me, so I decided to ask for a help and (hopefully) unveiling this assumption.

     

    Here are the details. I have dozens of thousands of container objects where each contains a char* buffer, and I want to parse them concurrently using std::istream and operator >>. This is simply to avoid reinventing a wheel (a string parser).

    Here is a code snippet:

     

    class DataContainer

    {

    public:

     

    ...

     

        /*! Reads integers from a buffer populated in the constructor.

        */

        void Parse() const

        {

            //represent myBuf as STL stream

            std::strstreambuf aDataBuf (myBuf, mySize);

            std::istream aDataStream (&aDataBuf);

            //aDataStream.imbue (std::locale ("C"));

     

            int n = 0;

            aDataStream >> n;

            for ( int i = 0; i < n; i++) {

                int k;

                assert (aDataStream.good());

                aDataStream >> k;

            }

        }

     

    private:

        char *   myBuf;

        int      mySize;

    };

     

     

    There is an array of 20,000+ of such DataContainers and a loop where Parse() method is called on each. The code running concurrently executes about 2x-5x slower than one running sequentially !!! Analyzing the hotspots (using Intel Parallel Amplifier) I have found the root-cause as follows:

     

    It is connected with critical section used to protect a common locale object. operator >>() inside creates a basic_istream::sentry object on the stack. Its constructor calls (through another method) ios_base::locale() which returns a std::locale object (see syntax below). So its copy constructor is called which calls Incref() to increment a reference counter. Incrementing reference counter is surrounded by a critical section.

    As all streams have a pointer to a shared locale object then there is a high contention.

     

    locale ios_base::getloc( ) const;

    locale __CLR_OR_THIS_CALL getloc() const

    {     // get locale

    return (*_Ploc);

    }

     

    Trying to set individual locale objects into each stream (if to remove comments on the line with imbue() above)does not help much though there is some minor performance improvement. Stepping with the debugger into STL code I see that strstreambuf and stream constructors still call Incref() for a global locale object, thereby still causing a high contention.

     

    Am I doing something wrong or is it a principal limitation of STL that the streams cannot be used concurrently ?

     

    Thank you very much in advance.

    Roman

    Tuesday, May 26, 2009 1:25 PM

Answers

All replies

  • Just in case, I'm using MS Visual Studio 2005.
    Tuesday, May 26, 2009 1:41 PM
  • I think this was fixed in VS2008 SP1.  The critical section was replaced by InterlockedIncrement().  Check the _MT_INCR() macro in <memory>. 

    Hans Passant.
    Tuesday, May 26, 2009 1:53 PM
    Moderator
  • Thank you Hans. This good news that this has been noticed and fixed.
    Tuesday, May 26, 2009 3:14 PM
  • Just installed VS2008 SP1 and found that ... the bug is still there !

    Here is the code. File c:\Program Files\Microsoft Visual Studio 9.0\VC\crt\src\xlocale:

    116            _CRTIMP2_PURE void __CLR_OR_THIS_CALL _Incref()   
    117                {    // safely increment the reference count   
    118                _BEGIN_LOCK(_LOCK_LOCALE)   
    119                    if (_Refs < (size_t)(-1))   
    120                        ++_Refs;   
    121                _END_LOCK()   
    122                }   
    123       
    124            _CRTIMP2_PURE facet *__CLR_OR_THIS_CALL _Decref()   
    125                {    // safely decrement the reference count, return this when dead   
    126                _BEGIN_LOCK(_LOCK_LOCALE)   
    127                    if (0 < _Refs && _Refs < (size_t)(-1))   
    128                        --_Refs;   
    129                    return (_Refs == 0 ? this : 0);   
    130                _END_LOCK()   
    131                }   

    (The code fully matches one in VS2005 SP1).

    The file xlocal is 80188 bytes and is dated March 10, 2007 (though the SP was in August 2008 and there are files in that directory dated July 29, 2008).
    So the question remains - is this a known bug and is it fixed ?

    Thank you.
    Roman
    Tuesday, June 09, 2009 9:00 PM
  • Ouch.  Yup, they forgot that one.

    Hans Passant.
    Tuesday, June 09, 2009 9:19 PM
    Moderator
  • I just checked the xlocale version dated July 16, 2009 (file size 91653 bytes) and see the same code.

    Hans, could you escalate this to the development team or let me know who to do this ? I am concerned whether the fix can really make the Dev 10 release. It impacts the project I am working on making the respective code serial instead of parallel :-(.

    Thank you,
    Roman


            _CRTIMP2_PURE void __CLR_OR_THIS_CALL _Incref()
                {    // safely increment the reference count
                _BEGIN_LOCK(_LOCK_LOCALE)
                    if (_Refs < (size_t)(-1))
                        ++_Refs;
                _END_LOCK()
                }

            _CRTIMP2_PURE facet *__CLR_OR_THIS_CALL _Decref()
                {    // safely decrement the reference count, return this when dead
                _BEGIN_LOCK(_LOCK_LOCALE)
                    if (0 < _Refs && _Refs < (size_t)(-1))
                        --_Refs;
                    return (_Refs == 0 ? this : 0);
                _END_LOCK()
                }

    Friday, September 25, 2009 7:23 AM
  • Post to connect.microsoft.com to let them know about this bug.

    Hans Passant.
    Friday, September 25, 2009 8:37 AM
    Moderator
  • Thanks. Submitted as https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=492561
    Monday, September 28, 2009 6:26 AM
  • Fixed in VC11.
    Monday, October 18, 2010 7:44 PM
  • Will this fix by chance be available in the upcoming VS2010 SP1 release?
    Thursday, January 27, 2011 7:14 PM
  • No, sorry. It would be too risky.
    Friday, January 28, 2011 3:25 AM