Can STL streams run concurrently ?
-
Tuesday, May 26, 2009 1:25 PM
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
All Replies
-
Tuesday, May 26, 2009 1:41 PMJust in case, I'm using MS Visual Studio 2005.
-
Tuesday, May 26, 2009 1:53 PMModeratorI think this was fixed in VS2008 SP1. The critical section was replaced by InterlockedIncrement(). Check the _MT_INCR() macro in <memory>.
Hans Passant.- Marked As Answer by Wesley Yao Monday, June 01, 2009 2:27 AM
- Unmarked As Answer by nobugzMVP, Moderator Tuesday, June 09, 2009 9:19 PM
-
Tuesday, May 26, 2009 3:14 PMThank you Hans. This good news that this has been noticed and fixed.
-
Tuesday, June 09, 2009 9:00 PMJust 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:19 PMModerator
Ouch. Yup, they forgot that one.
Hans Passant.- Marked As Answer by nobugzMVP, Moderator Sunday, October 04, 2009 4:24 PM
-
Friday, September 25, 2009 7:23 AMI 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 8:37 AMModeratorPost to connect.microsoft.com to let them know about this bug.
Hans Passant. -
Monday, September 28, 2009 6:26 AM
Thanks. Submitted as https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=492561- Marked As Answer by nobugzMVP, Moderator Sunday, October 04, 2009 4:24 PM
-
Monday, October 18, 2010 7:44 PMFixed in VC11.
-
Thursday, January 27, 2011 7:14 PMWill this fix by chance be available in the upcoming VS2010 SP1 release?
-
Friday, January 28, 2011 3:25 AMNo, sorry. It would be too risky.

