MSVC istream implementation locking buffer
I'm working with some existing code which is deserializing objects stored in text files (I potentially need to read tens of millions of these). The contents of the file are first read into a wstring
and then it makes a wistringstream
from that. Running the Very Sleepy profiler on the program shows that it is spending about 20% of its time in the following call stacks:
Mtxlock or RtlEnterCritialSection
std::_Mutex::_Lock
std::flush
std::basic_istream<wchar_t, std::char_traits<wchar_t> >::get
<rest of my program>
and similar ones with std::_Mutex::_Unlock
. I'm using Visual C++ 2008.
Looking in istream
, I see that it constructs a sentry
object which calls _Lock
and _Unlock
methods on the underlying basic_streambuf
. This in turn just call _Lock
and _Unlock
on a _Mutex
associated with that buffer. These are then defined as follows:
#if _MULTI_THREAD
// actually def开发者_运维技巧ines non-empty _Lock() and _Unlock() methods
#else /* _MULTI_THREAD */
void _Lock()
{ // do nothing
}
void _Unlock()
{ // do nothing
}
#endif /* _MULTI_THREAD */
It looks like _MULTI_THREAD is set in yvals.h
as
#define _MULTI_THREAD 1 /* nontrivial locks if multithreaded */
Now, I know there will never be another thread trying to access this buffer, but it looks to me like there's no way around this locking while using the standard iostreams, which seems both odd and frustrating. Am I missing something? Is there a workaround for this?
Check the value for Runtime Library in Project properties, C/C++, Code Generation. If it's multi-threaded, change it to a non-multithreaded version.
In any version after Visual C++ 7.1 (!), you are out of luck as it's been removed, and you are stuck with the multithreaded CRT.
The std::flush
seems senseless in your case. I can't see how you'd flush an istream
, so I suspect it's a result of a tie
. You may want to un-tie, i.e. call tie(NULL)
on your wistringstream
. That should also reduce the number of locks taken.
It turned out accessing the underlying buffer directly by replacing things like
c = _text_in->get();
with things like this
c = _text_in->rdbuf()->sbumpc();
fixed the problem and provided a big boost to performance.
精彩评论