Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r82566 - in trunk: boost/thread boost/thread/detail boost/thread/pthread libs/thread/test/sync/mutual_exclusion/once/call_once
From: vicente.botet_at_[hidden]
Date: 2013-01-20 12:06:34


Author: viboes
Date: 2013-01-20 12:06:33 EST (Sun, 20 Jan 2013)
New Revision: 82566
URL: http://svn.boost.org/trac/boost/changeset/82566

Log:
Thread: improve call_once using invoke/bind and rvalue references
Text files modified:
   trunk/boost/thread/detail/invoke.hpp | 2
   trunk/boost/thread/once.hpp | 6
   trunk/boost/thread/pthread/once.hpp | 246 +++++++++++++++++++++++++++++++++++++++
   trunk/boost/thread/pthread/once_atomic.hpp | 147 +++++++++++++++++++++++
   trunk/libs/thread/test/sync/mutual_exclusion/once/call_once/call_once_pass.cpp | 50 ++++++-
   5 files changed, 434 insertions(+), 17 deletions(-)

Modified: trunk/boost/thread/detail/invoke.hpp
==============================================================================
--- trunk/boost/thread/detail/invoke.hpp (original)
+++ trunk/boost/thread/detail/invoke.hpp 2013-01-20 12:06:33 EST (Sun, 20 Jan 2013)
@@ -31,6 +31,8 @@
     ! defined(BOOST_NO_CXX11_AUTO) && \
     ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
 
+#define BOOST_THREAD_PROVIDES_INVOKE
+
     // // bullets 1 and 2
 
     template <class Fp, class A0, class ...Args>

Modified: trunk/boost/thread/once.hpp
==============================================================================
--- trunk/boost/thread/once.hpp (original)
+++ trunk/boost/thread/once.hpp 2013-01-20 12:06:33 EST (Sun, 20 Jan 2013)
@@ -31,9 +31,9 @@
 {
   // template<class Callable, class ...Args> void
   // call_once(once_flag& flag, Callable&& func, Args&&... args);
-//template<typename Function>
-//inline void call_once(Function func,once_flag& flag)
-inline void call_once(void (*func)(),once_flag& flag)
+template<typename Function>
+inline void call_once(Function func,once_flag& flag)
+//inline void call_once(void (*func)(),once_flag& flag)
     {
         call_once(flag,func);
     }

Modified: trunk/boost/thread/pthread/once.hpp
==============================================================================
--- trunk/boost/thread/pthread/once.hpp (original)
+++ trunk/boost/thread/pthread/once.hpp 2013-01-20 12:06:33 EST (Sun, 20 Jan 2013)
@@ -12,11 +12,13 @@
 
 #include <boost/thread/detail/config.hpp>
 #include <boost/thread/detail/move.hpp>
+#include <boost/thread/detail/invoke.hpp>
 
 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
 #include <boost/thread/detail/delete.hpp>
 #include <boost/detail/no_exceptions_support.hpp>
 
+#include <boost/bind.hpp>
 #include <boost/assert.hpp>
 #include <boost/config/abi_prefix.hpp>
 
@@ -127,7 +129,23 @@
                 BOOST_TRY
                 {
                     pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
- f(boost::forward<ArgTypes>(args)...);
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+#if defined BOOST_THREAD_PROVIDES_INVOKE
+ detail::invoke(
+ thread_detail::decay_copy(boost::forward<Function>(f)),
+ thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
+ );
+#else
+ boost::bind(
+ thread_detail::decay_copy(boost::forward<Function>(f)),
+ thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
+ )();
+#endif
+#else
+ f(
+ thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
+ );
+#endif
                 }
                 BOOST_CATCH (...)
                 {
@@ -216,7 +234,11 @@
                 BOOST_TRY
                 {
                     pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::bind(f,p1)();
+#else
                     f(p1);
+#endif
                 }
                 BOOST_CATCH (...)
                 {
@@ -259,8 +281,12 @@
                 BOOST_TRY
                 {
                     pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
- f(p1, p2);
- }
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::bind(f,p1,p2)();
+#else
+ f(p1,p2);
+#endif
+ }
                 BOOST_CATCH (...)
                 {
                     flag.epoch=uninitialized_flag;
@@ -303,7 +329,219 @@
                 BOOST_TRY
                 {
                     pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
- f(p1, p2, p3);
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::bind(f,p1,p2,p3)();
+#else
+ f(p1,p2,p3);
+#endif
+ }
+ BOOST_CATCH (...)
+ {
+ flag.epoch=uninitialized_flag;
+ BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ flag.epoch=--thread_detail::once_global_epoch;
+ BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
+ }
+ else
+ {
+ while(flag.epoch==being_initialized)
+ {
+ BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
+ }
+ }
+ }
+ this_thread_epoch=thread_detail::once_global_epoch;
+ }
+ }
+
+ template<typename Function>
+ inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f)
+ {
+ static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
+ static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
+ thread_detail::uintmax_atomic_t const epoch=flag.epoch;
+ thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
+
+ if(epoch<this_thread_epoch)
+ {
+ pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
+
+ while(flag.epoch<=being_initialized)
+ {
+ if(flag.epoch==uninitialized_flag)
+ {
+ flag.epoch=being_initialized;
+ BOOST_TRY
+ {
+ pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
+ f();
+ }
+ BOOST_CATCH (...)
+ {
+ flag.epoch=uninitialized_flag;
+ BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ flag.epoch=--thread_detail::once_global_epoch;
+ BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
+ }
+ else
+ {
+ while(flag.epoch==being_initialized)
+ {
+ BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
+ }
+ }
+ }
+ this_thread_epoch=thread_detail::once_global_epoch;
+ }
+ }
+
+ template<typename Function, typename T1>
+ inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1)
+ {
+ static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
+ static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
+ thread_detail::uintmax_atomic_t const epoch=flag.epoch;
+ thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
+
+ if(epoch<this_thread_epoch)
+ {
+ pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
+
+ while(flag.epoch<=being_initialized)
+ {
+ if(flag.epoch==uninitialized_flag)
+ {
+ flag.epoch=being_initialized;
+ BOOST_TRY
+ {
+ pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::bind(
+ thread_detail::decay_copy(boost::forward<Function>(f)),
+ thread_detail::decay_copy(boost::forward<T1>(p1))
+ )();
+#else
+ f(
+ thread_detail::decay_copy(boost::forward<T1>(p1))
+ );
+#endif
+ }
+ BOOST_CATCH (...)
+ {
+ flag.epoch=uninitialized_flag;
+ BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ flag.epoch=--thread_detail::once_global_epoch;
+ BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
+ }
+ else
+ {
+ while(flag.epoch==being_initialized)
+ {
+ BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
+ }
+ }
+ }
+ this_thread_epoch=thread_detail::once_global_epoch;
+ }
+ }
+ template<typename Function, typename T1, typename T2>
+ inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2)
+ {
+ static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
+ static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
+ thread_detail::uintmax_atomic_t const epoch=flag.epoch;
+ thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
+
+ if(epoch<this_thread_epoch)
+ {
+ pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
+
+ while(flag.epoch<=being_initialized)
+ {
+ if(flag.epoch==uninitialized_flag)
+ {
+ flag.epoch=being_initialized;
+ BOOST_TRY
+ {
+ pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::bind(
+ thread_detail::decay_copy(boost::forward<Function>(f)),
+ thread_detail::decay_copy(boost::forward<T1>(p1)),
+ thread_detail::decay_copy(boost::forward<T1>(p2))
+ )();
+#else
+ f(
+ thread_detail::decay_copy(boost::forward<T1>(p1)),
+ thread_detail::decay_copy(boost::forward<T1>(p2))
+ );
+#endif
+ }
+ BOOST_CATCH (...)
+ {
+ flag.epoch=uninitialized_flag;
+ BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ flag.epoch=--thread_detail::once_global_epoch;
+ BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
+ }
+ else
+ {
+ while(flag.epoch==being_initialized)
+ {
+ BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
+ }
+ }
+ }
+ this_thread_epoch=thread_detail::once_global_epoch;
+ }
+ }
+
+ template<typename Function, typename T1, typename T2, typename T3>
+ inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3)
+ {
+ static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
+ static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
+ thread_detail::uintmax_atomic_t const epoch=flag.epoch;
+ thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
+
+ if(epoch<this_thread_epoch)
+ {
+ pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
+
+ while(flag.epoch<=being_initialized)
+ {
+ if(flag.epoch==uninitialized_flag)
+ {
+ flag.epoch=being_initialized;
+ BOOST_TRY
+ {
+ pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::bind(
+ thread_detail::decay_copy(boost::forward<Function>(f)),
+ thread_detail::decay_copy(boost::forward<T1>(p1)),
+ thread_detail::decay_copy(boost::forward<T1>(p2)),
+ thread_detail::decay_copy(boost::forward<T1>(p3))
+ )();
+#else
+ f(
+ thread_detail::decay_copy(boost::forward<T1>(p1)),
+ thread_detail::decay_copy(boost::forward<T1>(p2)),
+ thread_detail::decay_copy(boost::forward<T1>(p3))
+ );
+#endif
                 }
                 BOOST_CATCH (...)
                 {

Modified: trunk/boost/thread/pthread/once_atomic.hpp
==============================================================================
--- trunk/boost/thread/pthread/once_atomic.hpp (original)
+++ trunk/boost/thread/pthread/once_atomic.hpp 2013-01-20 12:06:33 EST (Sun, 20 Jan 2013)
@@ -14,7 +14,9 @@
 
 #include <boost/cstdint.hpp>
 #include <boost/thread/detail/move.hpp>
+#include <boost/thread/detail/invoke.hpp>
 #include <boost/detail/no_exceptions_support.hpp>
+#include <boost/bind.hpp>
 
 #include <boost/config/abi_prefix.hpp>
 
@@ -74,7 +76,23 @@
     {
       BOOST_TRY
       {
- f(boost::forward<ArgTypes>(args)...);
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+#if defined BOOST_THREAD_PROVIDES_INVOKE
+ detail::invoke(
+ thread_detail::decay_copy(boost::forward<Function>(f)),
+ thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
+ );
+#else
+ boost::bind(
+ thread_detail::decay_copy(boost::forward<Function>(f)),
+ thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
+ )();
+#endif
+#else
+ f(
+ thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
+ );
+#endif
       }
       BOOST_CATCH (...)
       {
@@ -112,7 +130,11 @@
     {
       BOOST_TRY
       {
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::bind(f,p1)();
+#else
         f(p1);
+#endif
       }
       BOOST_CATCH (...)
       {
@@ -131,7 +153,11 @@
     {
       BOOST_TRY
       {
- f(p1, p2);
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::bind(f,p1,p2)();
+#else
+ f(p1,p2);
+#endif
       }
       BOOST_CATCH (...)
       {
@@ -150,7 +176,30 @@
     {
       BOOST_TRY
       {
- f(p1, p2, p3);
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::bind(f,p1,p2,p3)();
+#else
+ f(p1,p2,p3);
+#endif
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+
+ template<typename Function>
+ inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+ f();
       }
       BOOST_CATCH (...)
       {
@@ -162,6 +211,98 @@
     }
   }
 
+ template<typename Function, typename T1>
+ inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::bind(
+ thread_detail::decay_copy(boost::forward<Function>(f)),
+ thread_detail::decay_copy(boost::forward<T1>(p1))
+ )();
+#else
+ f(
+ thread_detail::decay_copy(boost::forward<T1>(p1))
+ );
+#endif
+
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+ template<typename Function, typename T1, typename T2>
+ inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::bind(
+ thread_detail::decay_copy(boost::forward<Function>(f)),
+ thread_detail::decay_copy(boost::forward<T1>(p1)),
+ thread_detail::decay_copy(boost::forward<T1>(p2))
+ )();
+#else
+ f(
+ thread_detail::decay_copy(boost::forward<T1>(p1)),
+ thread_detail::decay_copy(boost::forward<T1>(p2))
+ );
+#endif
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+ template<typename Function, typename T1, typename T2, typename T3>
+ inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+#if defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::bind(
+ thread_detail::decay_copy(boost::forward<Function>(f)),
+ thread_detail::decay_copy(boost::forward<T1>(p1)),
+ thread_detail::decay_copy(boost::forward<T1>(p2)),
+ thread_detail::decay_copy(boost::forward<T1>(p3))
+ )();
+#else
+ f(
+ thread_detail::decay_copy(boost::forward<T1>(p1)),
+ thread_detail::decay_copy(boost::forward<T1>(p2)),
+ thread_detail::decay_copy(boost::forward<T1>(p3))
+ );
+#endif
+
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+
+
+
 #endif
 }
 

Modified: trunk/libs/thread/test/sync/mutual_exclusion/once/call_once/call_once_pass.cpp
==============================================================================
--- trunk/libs/thread/test/sync/mutual_exclusion/once/call_once/call_once_pass.cpp (original)
+++ trunk/libs/thread/test/sync/mutual_exclusion/once/call_once/call_once_pass.cpp 2013-01-20 12:06:33 EST (Sun, 20 Jan 2013)
@@ -17,9 +17,11 @@
 // struct once_flag;
 
 // template<class Callable, class ...Args>
-// void call_once(once_flag& flag, Callable func, Args&&... args);
+// void call_once(once_flag& flag, Callable&& func, Args&&... args);
 
 //#define BOOST_THREAD_VERSION 4
+#define BOOST_THREAD_USES_MOVE
+#define BOOST_THREAD_USES_MOVE
 
 #include <boost/thread/once.hpp>
 #include <boost/thread/thread.hpp>
@@ -76,8 +78,10 @@
 struct init1
 {
     static int called;
+ typedef void result_type;
 
     void operator()(int i) {called += i;}
+ void operator()(int i) const {called += i;}
 };
 
 int init1::called = 0;
@@ -89,10 +93,33 @@
     boost::call_once(flg1, init1(), 1);
 }
 
+boost::once_flag flg1_member BOOST_INIT_ONCE_INIT;
+
+struct init1_member
+{
+ static int called;
+ typedef void result_type;
+ void call(int i) {
+ called += i;
+ }
+};
+int init1_member::called = 0;
+
+void f1_member()
+{
+ init1_member o;
+#if defined BOOST_THREAD_PLATFORM_PTHREAD && defined BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::call_once(flg1_member, &init1_member::call, o, 1);
+#else
+ boost::call_once(flg1_member, boost::bind(&init1_member::call, o, 1));
+#endif
+}
 struct init2
 {
     static int called;
+ typedef void result_type;
 
+ void operator()(int i, int j) {called += i + j;}
     void operator()(int i, int j) const {called += i + j;}
 };
 
@@ -138,11 +165,11 @@
     boost::call_once(flg41, init41);
 }
 
-#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
-
 class MoveOnly
 {
 public:
+ typedef void result_type;
+
   BOOST_THREAD_MOVABLE_ONLY(MoveOnly)
   MoveOnly()
   {
@@ -155,8 +182,6 @@
   }
 };
 
-#endif
-
 int main()
 {
     // check basic functionality
@@ -201,12 +226,23 @@
         t1.join();
         BOOST_TEST(init2::called == 5);
     }
-#if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
+#if defined BOOST_THREAD_PLATFORM_PTHREAD
+ //&& defined BOOST_THREAD_PROVIDES_INVOKE
+ // check member function with 1 arg
+ {
+ boost::thread t0(f1_member);
+ boost::thread t1(f1_member);
+ t0.join();
+ t1.join();
+ BOOST_TEST(init1_member::called == 1);
+ }
+#endif // BOOST_THREAD_PLATFORM_PTHREAD
+#if defined BOOST_THREAD_PLATFORM_PTHREAD && defined BOOST_THREAD_PROVIDES_INVOKE
     {
         boost::once_flag f BOOST_INIT_ONCE_INIT;
         boost::call_once(f, MoveOnly(), MoveOnly());
     }
-#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
+#endif // BOOST_THREAD_PLATFORM_PTHREAD
     return boost::report_errors();
 }
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk