Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r84809 - in trunk: boost/thread libs/thread/doc libs/thread/test
From: vicente.botet_at_[hidden]
Date: 2013-06-16 17:27:59


Author: viboes
Date: 2013-06-16 17:27:59 EDT (Sun, 16 Jun 2013)
New Revision: 84809
URL: http://svn.boost.org/trac/boost/changeset/84809

Log:
Thread: added completion function on barrier class.

Added:
   trunk/libs/thread/test/test_barrier_size_fct.cpp (contents, props changed)
   trunk/libs/thread/test/test_barrier_void_fct.cpp (contents, props changed)
Text files modified:
   trunk/boost/thread/barrier.hpp | 215 +++++++++++++++++++++++++++++++++------
   trunk/libs/thread/doc/barrier.qbk | 69 +++++++++++-
   trunk/libs/thread/test/Jamfile.v2 | 2
   trunk/libs/thread/test/test_barrier.cpp | 2
   trunk/libs/thread/test/test_barrier_size_fct.cpp | 68 ++++++++++++
   trunk/libs/thread/test/test_barrier_void_fct.cpp | 67 ++++++++++++
   6 files changed, 379 insertions(+), 44 deletions(-)

Modified: trunk/boost/thread/barrier.hpp
==============================================================================
--- trunk/boost/thread/barrier.hpp Sun Jun 16 15:36:41 2013 (r84808)
+++ trunk/boost/thread/barrier.hpp 2013-06-16 17:27:59 EDT (Sun, 16 Jun 2013) (r84809)
@@ -17,51 +17,196 @@
 #include <boost/thread/condition_variable.hpp>
 #include <string>
 #include <stdexcept>
+#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
+#include <boost/function.hpp>
+#else
+#include <functional>
+#endif
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/is_void.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/utility/result_of.hpp>
 
 #include <boost/config/abi_prefix.hpp>
 
 namespace boost
 {
+ namespace thread_detail
+ {
+#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
+ typedef function<void()> void_completion_function;
+ typedef function<size_t()> size_completion_function;
+#else
+ typedef std::function<void()> void_completion_function;
+ typedef std::function<size_t()> size_completion_function;
+#endif
 
- class barrier
+ struct default_barrier_reseter
     {
- public:
- BOOST_THREAD_NO_COPYABLE( barrier )
+ unsigned int size_;
+ default_barrier_reseter(unsigned int size) :
+ size_(size)
+ {
+ }
+ unsigned int operator()()
+ {
+ return size_;
+ }
+ };
 
- barrier(unsigned int count)
- : m_threshold(count), m_count(count), m_generation(0)
- {
- if (count == 0)
- boost::throw_exception(thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero."));
- }
-
- bool wait()
- {
- boost::unique_lock<boost::mutex> lock(m_mutex);
- unsigned int gen = m_generation;
-
- if (--m_count == 0)
- {
- m_generation++;
- m_count = m_threshold;
- m_cond.notify_all();
- return true;
- }
-
- while (gen == m_generation)
- m_cond.wait(lock);
- return false;
- }
-
- private:
- mutex m_mutex;
- condition_variable m_cond;
- unsigned int m_threshold;
- unsigned int m_count;
- unsigned int m_generation;
+ struct void_functor_barrier_reseter
+ {
+ unsigned int size_;
+ void_completion_function fct_;template <typename F>
+#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
+ void_functor_barrier_reseter(unsigned int size, BOOST_THREAD_RV_REF(F) funct)
+ : size_(size), fct_(boost::move(funct))
+ {}
+#else
+ void_functor_barrier_reseter(unsigned int size, F funct)
+ : size_(size), fct_(funct)
+ {}
+#endif
+ unsigned int operator()()
+ {
+ fct_();
+ return size_;
+ }
+ };
+ struct void_fct_ptr_barrier_reseter
+ {
+ unsigned int size_;
+ void(*fct_)();
+ void_fct_ptr_barrier_reseter(unsigned int size, void(*funct)()) :
+ size_(size), fct_(funct)
+ {
+ }
+ unsigned int operator()()
+ {
+ fct_();
+ return size_;
+ }
     };
+ }
+ class barrier
+ {
+ static inline unsigned int check(unsigned int count)
+ {
+ if (count == 0) boost::throw_exception(
+ thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero."));
+ return count;
+ }
+ struct dummy
+ {
+ };
+
+ public:
+ BOOST_THREAD_NO_COPYABLE( barrier)
+
+ explicit barrier(unsigned int count) :
+ m_count(check(count)), m_generation(0), fct_(thread_detail::default_barrier_reseter(count))
+ {
+ }
+
+ template <typename F>
+ barrier(
+ unsigned int count,
+#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
+ BOOST_THREAD_RV_REF(F) funct,
+#else
+ F funct,
+#endif
+ typename enable_if<
+ typename is_void<typename result_of<F>::type>::type, dummy*
+ >::type=0
+ )
+ : m_count(check(count)),
+ m_generation(0),
+ fct_(thread_detail::void_functor_barrier_reseter(count,
+#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
+ boost::move(funct)
+#else
+ funct
+#endif
+ )
+ )
+ {
+ }
+
+ template <typename F>
+ barrier(
+ unsigned int count,
+#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
+ BOOST_THREAD_RV_REF(F) funct,
+#else
+ F funct,
+#endif
+ typename enable_if<
+ typename is_same<typename result_of<F>::type, std::size_t>::type, dummy*
+ >::type=0
+ )
+ : m_count(check(count)),
+ m_generation(0),
+ fct_(
+#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
+ boost::move(funct)
+#else
+ funct
+#endif
+ )
+ {
+ }
+
+ barrier(unsigned int count, void(*funct)()) :
+ m_count(check(count)), m_generation(0),
+ fct_(funct
+ ? thread_detail::size_completion_function(thread_detail::void_fct_ptr_barrier_reseter(count, funct))
+ : thread_detail::size_completion_function(thread_detail::default_barrier_reseter(count))
+ )
+ {
+ }
+ barrier(unsigned int count, std::size_t(*funct)()) :
+ m_count(check(count)), m_generation(0),
+ fct_(funct
+ ? thread_detail::size_completion_function(funct)
+ : thread_detail::size_completion_function(thread_detail::default_barrier_reseter(count))
+ )
+ {
+ }
+
+ bool wait()
+ {
+ boost::unique_lock < boost::mutex > lock(m_mutex);
+ unsigned int gen = m_generation;
+
+ if (--m_count == 0)
+ {
+ m_generation++;
+ m_count = fct_();
+ BOOST_ASSERT(m_count != 0);
+ m_cond.notify_all();
+ return true;
+ }
+
+ while (gen == m_generation)
+ m_cond.wait(lock);
+ return false;
+ }
+
+ void count_down_and_wait()
+ {
+ wait();
+ }
+
+ private:
+ mutex m_mutex;
+ condition_variable m_cond;
+ unsigned int m_count;
+ unsigned int m_generation;
+ thread_detail::size_completion_function fct_;
+ };
 
-} // namespace boost
+} // namespace boost
 
 #include <boost/config/abi_suffix.hpp>
 

Modified: trunk/libs/thread/doc/barrier.qbk
==============================================================================
--- trunk/libs/thread/doc/barrier.qbk Sun Jun 16 15:36:41 2013 (r84808)
+++ trunk/libs/thread/doc/barrier.qbk 2013-06-16 17:27:59 EDT (Sun, 16 Jun 2013) (r84809)
@@ -1,11 +1,12 @@
 [/
   (C) Copyright 2007-8 Anthony Williams.
+ (C) Copyright 2013 Vicente J. Botet Escriba.
   Distributed under the Boost Software License, Version 1.0.
   (See accompanying file LICENSE_1_0.txt or copy at
   http://www.boost.org/LICENSE_1_0.txt).
 ]
 
-[section:barriers Barriers]
+[section:barriers Barriers -- EXTENSION]
 
 A barrier is a simple concept. Also known as a ['rendezvous], it is a synchronization point between multiple threads. The barrier is
 configured for a particular number of threads (`n`), and as threads reach the barrier they must wait until all `n` threads have
@@ -22,14 +23,18 @@
         barrier& operator=(barrier const&) = delete;
 
         barrier(unsigned int count);
+ template <typename F>
+ barrier(unsigned int count, F&&);
+
         ~barrier();
 
         bool wait();
+ void count_down_and_wait();
     };
 
 Instances of __barrier__ are not copyable or movable.
 
-[heading Constructor]
+[section Constructor `barrier(unsigned int)`]
 
     barrier(unsigned int count);
 
@@ -41,7 +46,24 @@
 
 ]
 
-[heading Destructor]
+[endsect]
+[section Constructor `barrier(unsigned int, F&&)`]
+
+ barrier(unsigned int count, F&& completion);
+
+[variablelist
+
+[[Requires:] [The result type of the completion function call `completion()` is `void` or `unsigned int`.]]
+
+[[Effects:] [Construct a barrier for `count` threads and a completion function `completion`.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+
+
+[endsect]
+[section Destructor `~barrier()`]
 
     ~barrier();
 
@@ -55,24 +77,55 @@
 
 ]
 
-[heading Member function `wait`]
+[endsect]
+[section Member Function `wait()`]
 
     bool wait();
 
 [variablelist
 
-[[Effects:] [Block until `count` threads have called `wait` on `*this`. When the `count`-th thread calls `wait`, all waiting threads
-are unblocked, and the barrier is reset. ]]
+[[Effects:] [Block until `count` threads have called `wait` or `count_down_and_wait` on `*this`. When the `count`-th thread calls `wait`, the barrier is reset and all waiting threads are unblocked.
+The reset depends on whether the barrier was constructed with a completion function or not. If there is no completion function or if the completion function result is void, the reset consists in restoring the original count. Otherwise the rest consist in assigning the result of the completion function (which must not be 0).]]
 
 [[Returns:] [`true` for exactly one thread from each batch of waiting threads, `false` otherwise.]]
 
-[[Throws:] [__thread_resource_error__ if an error occurs. __thread_interrupted__ if the wait was interrupted by a call to
-__interrupt__ on the __thread__ object associated with the current thread of execution.]]
+[[Throws:] [
+
+- __thread_resource_error__ if an error occurs.
+
+- __thread_interrupted__ if the wait was interrupted by a call to
+__interrupt__ on the __thread__ object associated with the current thread of execution.
+
+]]
 
 [[Notes:] [`wait()` is an ['interruption point].]]
 
 ]
 
 [endsect]
+[section Member Function `count_down_and_wait()`]
+
+ void count_down_and_wait();
+
+[variablelist
+
+[[Effects:] [Block until `count` threads have called `wait` or `count_down_and_wait` on `*this`. When the `count`-th thread calls `wait`, the barrier is reset and all waiting threads are unblocked.
+The reset depends on whether the barrier was constructed with a completion function or not. If there is no completion function or if the completion function result is void, the reset consists in restoring the original count. Otherwise the rest consist in assigning the result of the completion function (which must not be 0).]]
+
+[[Throws:] [
+
+- __thread_resource_error__ if an error occurs.
 
+- __thread_interrupted__ if the wait was interrupted by a call to
+__interrupt__ on the __thread__ object associated with the current thread of execution.
+
+]]
+
+[[Notes:] [`count_down_and_wait()` is an ['interruption point].]]
+
+]
+
+
+[endsect]
+[endsect]
 [endsect]

Modified: trunk/libs/thread/test/Jamfile.v2
==============================================================================
--- trunk/libs/thread/test/Jamfile.v2 Sun Jun 16 15:36:41 2013 (r84808)
+++ trunk/libs/thread/test/Jamfile.v2 2013-06-16 17:27:59 EDT (Sun, 16 Jun 2013) (r84809)
@@ -231,6 +231,8 @@
           [ thread-test test_condition.cpp ]
           [ thread-test test_once.cpp ]
           [ thread-run test_barrier.cpp ]
+ [ thread-run test_barrier_void_fct.cpp ]
+ [ thread-run test_barrier_size_fct.cpp ]
           [ thread-test test_lock_concept.cpp ]
           [ thread-test test_generic_locks.cpp ]
           [ thread-run test_latch.cpp ]

Modified: trunk/libs/thread/test/test_barrier.cpp
==============================================================================
--- trunk/libs/thread/test/test_barrier.cpp Sun Jun 16 15:36:41 2013 (r84808)
+++ trunk/libs/thread/test/test_barrier.cpp 2013-06-16 17:27:59 EDT (Sun, 16 Jun 2013) (r84809)
@@ -18,7 +18,7 @@
 namespace {
 
 // Shared variables for generation barrier test
-const int N_THREADS=10;
+const int N_THREADS=3;
 boost::barrier gen_barrier(N_THREADS);
 boost::mutex mutex;
 long global_parameter;

Added: trunk/libs/thread/test/test_barrier_size_fct.cpp
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/libs/thread/test/test_barrier_size_fct.cpp 2013-06-16 17:27:59 EDT (Sun, 16 Jun 2013) (r84809)
@@ -0,0 +1,68 @@
+// (C) Copyright 2013 Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#define BOOST_THREAD_PROVIDES_INTERRUPTIONS
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/thread.hpp>
+#include <boost/thread/barrier.hpp>
+
+#include <boost/detail/lightweight_test.hpp>
+#include <vector>
+
+namespace {
+
+
+// Shared variables for generation barrier test
+long global_parameter;
+const int N_THREADS=3;
+
+std::size_t size_fct() {
+ global_parameter++;
+ return N_THREADS;
+}
+
+boost::barrier gen_barrier(N_THREADS, size_fct);
+
+void barrier_thread()
+{
+ for (int i = 0; i < 5; ++i)
+ {
+ gen_barrier.count_down_and_wait();
+ }
+}
+
+} // namespace
+
+void test_barrier()
+{
+ boost::thread_group g;
+ global_parameter = 0;
+
+ try
+ {
+ for (int i = 0; i < N_THREADS; ++i)
+ g.create_thread(&barrier_thread);
+ g.join_all();
+ }
+ catch(...)
+ {
+ g.interrupt_all();
+ g.join_all();
+ throw;
+ }
+
+ BOOST_TEST(global_parameter==5);
+
+}
+
+int main()
+{
+
+ test_barrier();
+ return boost::report_errors();
+}
+

Added: trunk/libs/thread/test/test_barrier_void_fct.cpp
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/libs/thread/test/test_barrier_void_fct.cpp 2013-06-16 17:27:59 EDT (Sun, 16 Jun 2013) (r84809)
@@ -0,0 +1,67 @@
+// (C) Copyright 2013 Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#define BOOST_THREAD_PROVIDES_INTERRUPTIONS
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/thread.hpp>
+#include <boost/thread/barrier.hpp>
+
+#include <boost/detail/lightweight_test.hpp>
+#include <vector>
+
+namespace {
+
+
+// Shared variables for generation barrier test
+long global_parameter;
+
+void void_fct() {
+ global_parameter++;
+}
+
+const int N_THREADS=3;
+boost::barrier gen_barrier(N_THREADS, void_fct);
+
+void barrier_thread()
+{
+ for (int i = 0; i < 5; ++i)
+ {
+ gen_barrier.count_down_and_wait();
+ }
+}
+
+} // namespace
+
+void test_barrier()
+{
+ boost::thread_group g;
+ global_parameter = 0;
+
+ try
+ {
+ for (int i = 0; i < N_THREADS; ++i)
+ g.create_thread(&barrier_thread);
+ g.join_all();
+ }
+ catch(...)
+ {
+ g.interrupt_all();
+ g.join_all();
+ throw;
+ }
+
+ BOOST_TEST(global_parameter==5);
+
+}
+
+int main()
+{
+
+ test_barrier();
+ 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