This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
std::call_once without TLS
- From: Jonathan Wakely <jwakely dot gcc at gmail dot com>
- To: "libstdc++" <libstdc++ at gcc dot gnu dot org>
- Date: Fri, 3 Apr 2009 00:38:51 +0100
- Subject: std::call_once without TLS
when _GLIBCXX_HAVE_TLS is not defined, call_once uses a global lock to
protect the global __once_functor. All threads manipulate the same
static lock object. These means that two threads calling call_once
(even on different once_flags) will both try to call
unique_lock::lock() on the same object. Isn't that unsafe? Separate
threads should use different unique_lock instances that share a mutex.
Am I missing something, or would a change like this (not tested or
even compiled) be better, and also ensure the mutex doesn't stay
locked if the std::function::operator= throws?
Index: include/std/mutex
===================================================================
--- include/std/mutex (revision 145468)
+++ include/std/mutex (working copy)
@@ -733,9 +733,10 @@ namespace std
}
#else
extern function<void()> __once_functor;
+ extern unique_lock<mutex>* __once_functor_lock;
- extern unique_lock<mutex>&
- __get_once_functor_lock();
+ extern mutex&
+ __get_once_mutex();
#endif
extern "C" void __once_proxy();
@@ -750,18 +751,13 @@ namespace std
__once_callable = &__bound_functor;
__once_call = &__once_call_impl<decltype(__bound_functor)>;
#else
- unique_lock<mutex>& __functor_lock = __get_once_functor_lock();
- __functor_lock.lock();
+ unique_lock<mutex> __functor_lock(__get_once_mutex());
__once_functor = bind(__f, __args...);
+ __once_functor_lock = &__functor_lock;
#endif
int __e = __gthread_once(&(__once._M_once), &__once_proxy);
-#ifndef _GLIBCXX_HAVE_TLS
- if (__functor_lock)
- __functor_lock.unlock();
-#endif
-
if (__e)
__throw_system_error(__e);
}
Index: src/mutex.cc
===================================================================
--- src/mutex.cc (revision 145468)
+++ src/mutex.cc (working copy)
@@ -30,18 +30,6 @@
#include <mutex>
#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
-#ifndef _GLIBCXX_HAVE_TLS
-namespace
-{
- std::mutex&
- get_once_mutex()
- {
- static std::mutex once_mutex;
- return once_mutex;
- }
-}
-#endif
-
namespace std
{
const defer_lock_t defer_lock = defer_lock_t();
@@ -60,11 +48,13 @@ namespace std
template class function<void()>;
function<void()> __once_functor;
- unique_lock<mutex>&
- __get_once_functor_lock()
+ unique_lock<mutex>* __once_functor_lock;
+
+ mutex&
+ __get_once_mutex()
{
- static unique_lock<mutex> once_functor_lock(get_once_mutex(), defer_lock);
- return once_functor_lock;
+ static mutex once_mutex;
+ return once_mutex;
}
#endif
@@ -74,7 +64,7 @@ namespace std
{
#ifndef _GLIBCXX_HAVE_TLS
function<void()> __once_call = std::move(__once_functor);
- __get_once_functor_lock().unlock();
+ __once_functor_lock->unlock();
#endif
__once_call();
}
@@ -60,11 +48,13 @@ namespace std
template class function<void()>;
function<void()> __once_functor;
- unique_lock<mutex>&
- __get_once_functor_lock()
+ unique_lock<mutex>* __once_functor_lock;
+
+ mutex&
+ __get_once_mutex()
{
- static unique_lock<mutex> once_functor_lock(get_once_mutex(), defer_lock);
- return once_functor_lock;
+ static mutex once_mutex;
+ return once_mutex;
}
#endif
@@ -74,7 +64,7 @@ namespace std
{
#ifndef _GLIBCXX_HAVE_TLS
function<void()> __once_call = std::move(__once_functor);
- __get_once_functor_lock().unlock();
+ __once_functor_lock->unlock();
#endif
__once_call();
}