|
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