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 defines 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?
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.