This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: libstdc++/7445: poor performance of std::locale::classic() inmulti-threaded applications
- From: Andrew Pollard <Andrew dot Pollard at brooks-pri dot com>
- To: bkoz at gcc dot gnu dot org
- Cc: shurik at sequoiap dot com, libstdc++ at gcc dot gnu dot org
- Date: Fri, 02 Aug 2002 14:51:27 +0100
- Subject: Re: libstdc++/7445: poor performance of std::locale::classic() inmulti-threaded applications
- Organization: Brooks-PRI Automation, Planning & Logistics Solutions
Hi There,
The recent checkin to libstdc++--v3/src/locale.cc that went into V3.2 (and
the trunk) isn't really correct - it probably works, but there is a problem
if two threads call the method at the same time.
There was a reason that I locked the entire method, so that _S_classic is
guaranteed to only be set once. With the code right now, there are a couple
of problems....
a) If two threads call the method at the same time when _S_classic isn't set,
one of them will obtain the lock, construct the internals, set _S_classic
and then exit, at which point the 2nd will get the lock and reconstruct the
internals and set _S_classic again.
b) If one thread is in the process of constructing the internals and setting
_S_classic (and it has done the _S_classic assignment, but not yet
constructed the c_locate object), a 2nd thread calling the method will
immediately return the not yet constructed c_locale object.
I think these two problems can be worked around.
a) Have a 2nd check for _S_classic after the auto lock, to handle the above
case "a"
b) set _S_classic as the last thing that the method does to handle the above
case "b"
A tentative version of this follows (assuming pointer reads and writes are
atomic - which if they aren't this is the least of the potential problems :-)
----------------------------------------------------------------------------------
const locale&
locale::classic()
{
if (!_S_classic)
{
static _STL_mutex_lock __lock __STL_MUTEX_INITIALIZER;
_STL_auto_lock __auto(__lock);
if (!_S_classic)
{
locale::_Impl* __tmp_S_classic = 0;
try
{
// 26 Standard facets, 2 references.
// One reference for _M_classic, one for _M_global
facet** f = new(&facet_vec) facet*[_GLIBCPP_NUM_FACETS];
for (size_t __i = 0; __i < _GLIBCPP_NUM_FACETS; ++__i)
f[__i] = 0;
__tmp_S_classic = new (&c_locale_impl) _Impl(f, 2, true);
new (&c_locale) locale(__tmp_S_classic);
_S_classic = _S_global = __tmp_S_classic;
}
catch(...)
{
// Just call destructor, so that locale_impl_c's memory is
// not deallocated via a call to delete.
if (__tmp_S_classic)
__tmp_S_classic->~_Impl();
_S_classic = _S_global = 0;
__throw_exception_again;
}
}
}
return c_locale;
}
----------------------------------------------------------------------------------
Andrew.
--
Andrew Pollard - Senior Software Engineer (APF)
Brooks-PRI Automation - Planning and Logistics Solutions
Email: Andrew.Pollard@brooks-pri.com - Tel: +44 (0)118 9215603