libstdc++/7445: poor performance of std::locale::classic() in multi-threaded applications

Andrew Pollard Andrew.Pollard@brooks-pri.com
Fri Aug 2 06:51:00 GMT 2002


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



More information about the Libstdc++ mailing list