diff options
Diffstat (limited to 'boost/thread')
57 files changed, 6030 insertions, 2281 deletions
diff --git a/boost/thread/caller_context.hpp b/boost/thread/caller_context.hpp index 1e341686b0..dc50a05f97 100644 --- a/boost/thread/caller_context.hpp +++ b/boost/thread/caller_context.hpp @@ -1,4 +1,4 @@ -// (C) Copyright 2013 Vicente J. Botet Escriba +// (C) Copyright 2013,2015 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) @@ -12,6 +12,7 @@ #include <boost/thread/thread.hpp> #endif #include <boost/current_function.hpp> +#include <boost/io/ios_state.hpp> #include <iomanip> #include <boost/config/abi_prefix.hpp> @@ -43,9 +44,11 @@ namespace boost #endif { io::ios_flags_saver ifs(os); - os << ctx.filename << "[" + os << std::setw(50) << ctx.filename << "[" << std::setw(4) << std::right << std::dec<< ctx.lineno << "] "; +#if defined BOOST_THREAD_USES_LOG_CURRENT_FUNCTION os << ctx.func << " " ; +#endif } return os; } diff --git a/boost/thread/concurrent_queues/deque_adaptor.hpp b/boost/thread/concurrent_queues/deque_adaptor.hpp new file mode 100644 index 0000000000..a8f45f863f --- /dev/null +++ b/boost/thread/concurrent_queues/deque_adaptor.hpp @@ -0,0 +1,209 @@ +#ifndef BOOST_THREAD_CONCURRENT_DEQUE_ADAPTOR_HPP +#define BOOST_THREAD_CONCURRENT_DEQUE_ADAPTOR_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> +#include <boost/thread/concurrent_queues/deque_base.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ +namespace detail +{ + + template <typename Queue> + class deque_adaptor_copyable_only : + public boost::deque_base<typename Queue::value_type, typename Queue::size_type> + { + Queue queue; + public: + typedef typename Queue::value_type value_type; + typedef typename Queue::size_type size_type; + + // Constructors/Assignment/Destructors + deque_adaptor_copyable_only() {} + + // Observers + bool empty() const { return queue.empty(); } + bool full() const { return queue.full(); } + size_type size() const { return queue.size(); } + bool closed() const { return queue.closed(); } + + // Modifiers + void close() { queue.close(); } + + void push_back(const value_type& x) { queue.push_back(x); } + + void pull_front(value_type& x) { queue.pull_front(x); }; + value_type pull_front() { return queue.pull_front(); } + + queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); } + queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); } + + queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); } + queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); } + + queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); } + queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); } + + }; + template <typename Queue> + class deque_adaptor_movable_only : + public boost::deque_base<typename Queue::value_type, typename Queue::size_type> + { + Queue queue; + public: + typedef typename Queue::value_type value_type; + typedef typename Queue::size_type size_type; + + // Constructors/Assignment/Destructors + + deque_adaptor_movable_only() {} + + // Observers + bool empty() const { return queue.empty(); } + bool full() const { return queue.full(); } + size_type size() const { return queue.size(); } + bool closed() const { return queue.closed(); } + + // Modifiers + void close() { queue.close(); } + + + void pull_front(value_type& x) { queue.pull_front(x); }; + // enable_if is_nothrow_copy_movable<value_type> + value_type pull_front() { return queue.pull_front(); } + + queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); } + + queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); } + + queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); } + + void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); } + queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); } + queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); } + queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); } + }; + + template <typename Queue> + class deque_adaptor_copyable_and_movable : + public boost::deque_base<typename Queue::value_type, typename Queue::size_type> + { + Queue queue; + public: + typedef typename Queue::value_type value_type; + typedef typename Queue::size_type size_type; + + // Constructors/Assignment/Destructors + + deque_adaptor_copyable_and_movable() {} + + // Observers + bool empty() const { return queue.empty(); } + bool full() const { return queue.full(); } + size_type size() const { return queue.size(); } + bool closed() const { return queue.closed(); } + + // Modifiers + void close() { queue.close(); } + + + void push_back(const value_type& x) { queue.push_back(x); } + + void pull_front(value_type& x) { queue.pull_front(x); }; + // enable_if is_nothrow_copy_movable<value_type> + value_type pull_front() { return queue.pull_front(); } + + queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); } + queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); } + + queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); } + queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); } + + queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); } + queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); } + + void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); } + queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); } + queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); } + queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); } + }; + + + template <class Q, class T, +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#if defined __GNUC__ && ! defined __clang__ +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__) + bool Copyable = is_copy_constructible<T>::value, + bool Movable = true +#else + bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value, + bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value +#endif // __GNUC__ +#elif defined _MSC_VER +#if _MSC_VER < 1700 + bool Copyable = is_copy_constructible<T>::value, + bool Movable = true +#else + bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value, + bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value +#endif // _MSC_VER +#else + bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value, + bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value +#endif +#else + bool Copyable = is_copy_constructible<T>::value, + bool Movable = has_move_emulation_enabled<T>::value +#endif + > + struct deque_adaptor; + + template <class Q, class T> + struct deque_adaptor<Q, T, true, true> { + typedef deque_adaptor_copyable_and_movable<Q> type; + }; + template <class Q, class T> + struct deque_adaptor<Q, T, true, false> { + typedef deque_adaptor_copyable_only<Q> type; + }; + template <class Q, class T> + struct deque_adaptor<Q, T, false, true> { + typedef deque_adaptor_movable_only<Q> type; + }; + +} + + template <typename Queue> + class deque_adaptor : + public detail::deque_adaptor<Queue, typename Queue::value_type>::type + { + public: + typedef typename Queue::value_type value_type; + typedef typename Queue::size_type size_type; + // Constructors/Assignment/Destructors + virtual ~deque_adaptor() {}; + }; +} +using concurrent::deque_adaptor; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/deque_base.hpp b/boost/thread/concurrent_queues/deque_base.hpp new file mode 100644 index 0000000000..f76e8a761d --- /dev/null +++ b/boost/thread/concurrent_queues/deque_base.hpp @@ -0,0 +1,202 @@ +#ifndef BOOST_THREAD_CONCURRENT_DEQUE_BASE_HPP +#define BOOST_THREAD_CONCURRENT_DEQUE_BASE_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> +#include <boost/type_traits/conditional.hpp> +#include <boost/type_traits/is_copy_constructible.hpp> + + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ +namespace detail +{ + + template <typename ValueType, class SizeType> + class deque_base_copyable_only + { + public: + typedef ValueType value_type; + typedef SizeType size_type; + + // Constructors/Assignment/Destructors + virtual ~deque_base_copyable_only() {}; + + // Observers + virtual bool empty() const = 0; + virtual bool full() const = 0; + virtual size_type size() const = 0; + virtual bool closed() const = 0; + + // Modifiers + virtual void close() = 0; + + virtual void push_back(const value_type& x) = 0; + + virtual void pull_front(value_type&) = 0; + virtual value_type pull_front() = 0; + + virtual queue_op_status try_push_back(const value_type& x) = 0; + virtual queue_op_status try_pull_front(value_type&) = 0; + + virtual queue_op_status nonblocking_push_back(const value_type& x) = 0; + virtual queue_op_status nonblocking_pull_front(value_type&) = 0; + + virtual queue_op_status wait_push_back(const value_type& x) = 0; + virtual queue_op_status wait_pull_front(value_type& elem) = 0; + + }; + + template <typename ValueType, class SizeType> + class deque_base_movable_only + { + public: + typedef ValueType value_type; + typedef SizeType size_type; + // Constructors/Assignment/Destructors + virtual ~deque_base_movable_only() {}; + + // Observers + virtual bool empty() const = 0; + virtual bool full() const = 0; + virtual size_type size() const = 0; + virtual bool closed() const = 0; + + // Modifiers + virtual void close() = 0; + + virtual void pull_front(value_type&) = 0; + // enable_if is_nothrow_movable<value_type> + virtual value_type pull_front() = 0; + + virtual queue_op_status try_pull_front(value_type&) = 0; + + virtual queue_op_status nonblocking_pull_front(value_type&) = 0; + + virtual queue_op_status wait_pull_front(value_type& elem) = 0; + + virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + }; + + + template <typename ValueType, class SizeType> + class deque_base_copyable_and_movable + { + public: + typedef ValueType value_type; + typedef SizeType size_type; + // Constructors/Assignment/Destructors + virtual ~deque_base_copyable_and_movable() {}; + + + // Observers + virtual bool empty() const = 0; + virtual bool full() const = 0; + virtual size_type size() const = 0; + virtual bool closed() const = 0; + + // Modifiers + virtual void close() = 0; + + virtual void push_back(const value_type& x) = 0; + + virtual void pull_front(value_type&) = 0; + // enable_if is_nothrow_copy_movable<value_type> + virtual value_type pull_front() = 0; + + virtual queue_op_status try_push_back(const value_type& x) = 0; + virtual queue_op_status try_pull_front(value_type&) = 0; + + virtual queue_op_status nonblocking_push_back(const value_type& x) = 0; + virtual queue_op_status nonblocking_pull_front(value_type&) = 0; + + virtual queue_op_status wait_push_back(const value_type& x) = 0; + virtual queue_op_status wait_pull_front(value_type& elem) = 0; + + virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + }; + + template <class T, class ST, +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#if defined __GNUC__ && ! defined __clang__ +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__) + bool Copyable = is_copy_constructible<T>::value, + bool Movable = true +#else + bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value, + bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value +#endif // __GNUC__ +#elif defined _MSC_VER +#if _MSC_VER < 1700 + bool Copyable = is_copy_constructible<T>::value, + bool Movable = true +#else + bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value, + bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value +#endif // _MSC_VER +#else + bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value, + bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value +#endif +#else + bool Copyable = is_copy_constructible<T>::value, + bool Movable = has_move_emulation_enabled<T>::value +#endif + > + struct deque_base; + + template <class T, class ST> + struct deque_base<T, ST, true, true> { + typedef deque_base_copyable_and_movable<T, ST> type; + }; + template <class T, class ST> + struct deque_base<T, ST, true, false> { + typedef deque_base_copyable_only<T, ST> type; + }; + template <class T, class ST> + struct deque_base<T, ST, false, true> { + typedef deque_base_movable_only<T, ST> type; + }; + +} + + template <class ValueType, class SizeType=std::size_t> + class deque_base : + public detail::deque_base<ValueType, SizeType>::type + { + public: + typedef ValueType value_type; + typedef SizeType size_type; + // Constructors/Assignment/Destructors + virtual ~deque_base() {}; + }; + +} +using concurrent::deque_base; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/deque_views.hpp b/boost/thread/concurrent_queues/deque_views.hpp new file mode 100644 index 0000000000..5715fb88cf --- /dev/null +++ b/boost/thread/concurrent_queues/deque_views.hpp @@ -0,0 +1,165 @@ +#ifndef BOOST_THREAD_QUEUE_VIEWS_HPP +#define BOOST_THREAD_QUEUE_VIEWS_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> +#include <boost/thread/concurrent_queues/deque_base.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ + + template <typename Queue> + class deque_back_view + { + Queue* queue; + public: + typedef typename Queue::value_type value_type; + typedef typename Queue::size_type size_type; + + // Constructors/Assignment/Destructors + deque_back_view(Queue& q) BOOST_NOEXCEPT : queue(&q) {} + + // Observers + bool empty() const { return queue->empty(); } + bool full() const { return queue->full(); } + size_type size() const { return queue->size(); } + bool closed() const { return queue->closed(); } + + // Modifiers + void close() { queue->close(); } + + void push(const value_type& x) { queue->push_back(x); } + + void pull(value_type& x) { queue->pull_back(x); } + // enable_if is_nothrow_copy_movable<value_type> + value_type pull() { return queue->pull_back(); } + + queue_op_status try_push(const value_type& x) { return queue->try_push_back(x); } + + queue_op_status try_pull(value_type& x) { return queue->try_pull_back(x); } + + queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_back(x); } + + queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_back(x); } + + queue_op_status wait_push(const value_type& x) { return queue->wait_push_back(x); } + queue_op_status wait_pull(value_type& x) { return queue->wait_pull_back(x); } + + void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_back(boost::move(x)); } + queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_back(boost::move(x)); } + queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_back(boost::move(x)); } + queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_back(boost::move(x)); } + }; + + template <typename Queue> + class deque_front_view + { + Queue* queue; + public: + typedef typename Queue::value_type value_type; + typedef typename Queue::size_type size_type; + + // Constructors/Assignment/Destructors + deque_front_view(Queue& q) BOOST_NOEXCEPT : queue(&q) {} + + // Observers + bool empty() const { return queue->empty(); } + bool full() const { return queue->full(); } + size_type size() const { return queue->size(); } + bool closed() const { return queue->closed(); } + + // Modifiers + void close() { queue->close(); } + + void push(const value_type& x) { queue->push_front(x); } + + void pull(value_type& x) { queue->pull_front(x); }; + // enable_if is_nothrow_copy_movable<value_type> + value_type pull() { return queue->pull_front(); } + + queue_op_status try_push(const value_type& x) { return queue->try_push_front(x); } + + queue_op_status try_pull(value_type& x) { return queue->try_pull_front(x); } + + queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_front(x); } + + queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_front(x); } + + queue_op_status wait_push(const value_type& x) { return queue->wait_push_front(x); } + queue_op_status wait_pull(value_type& x) { return queue->wait_pull_front(x); } + void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_front(forward<value_type>(x)); } + queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_front(forward<value_type>(x)); } + queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_front(forward<value_type>(x)); } + queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_front(forward<value_type>(x)); } + + }; + +#if ! defined BOOST_NO_CXX11_TEMPLATE_ALIASES + + template <class T> + using deque_back = deque_back_view<deque_base<T> > ; + template <class T> + using deque_front = deque_front_view<deque_base<T> > ; + +#else + + template <class T> + struct deque_back : deque_back_view<deque_base<T> > + { + typedef deque_back_view<deque_base<T> > base_type; + deque_back(deque_base<T>& q) BOOST_NOEXCEPT : base_type(q) {} + }; + template <class T> + struct deque_front : deque_front_view<deque_base<T> > + { + typedef deque_front_view<deque_base<T> > base_type; + deque_front(deque_base<T>& q) BOOST_NOEXCEPT : base_type(q) {} + + }; + +#endif + +// template <class Queue> +// deque_back_view<Queue> back(Queue & q) { return deque_back_view<Queue>(q); } +// template <class Queue> +// deque_front_view<Queue> front(Queue & q) { return deque_front_view<Queue>(q); } +//#if 0 +// template <class T> +// deque_back<T> back(deque_base<T> & q) { return deque_back<T>(q); } +// template <class T> +// deque_front<T> front(deque_base<T> & q) { return deque_front<T>(q); } +//#else +// template <class T> +// typename deque_back<T>::type back(deque_base<T> & q) { return typename deque_back<T>::type(q); } +// template <class T> +// typename deque_front<T>::type front(deque_base<T> & q) { return typename deque_front<T>::type(q); } +//#endif +} + +using concurrent::deque_back_view; +using concurrent::deque_front_view; +using concurrent::deque_back; +using concurrent::deque_front; +//using concurrent::back; +//using concurrent::front; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/detail/sync_deque_base.hpp b/boost/thread/concurrent_queues/detail/sync_deque_base.hpp new file mode 100644 index 0000000000..877e1e2eb4 --- /dev/null +++ b/boost/thread/concurrent_queues/detail/sync_deque_base.hpp @@ -0,0 +1,223 @@ +#ifndef BOOST_THREAD_CONCURRENT_QUEUES_DETAIL_SYNC_DEQUE_BASE_HPP +#define BOOST_THREAD_CONCURRENT_QUEUES_DETAIL_SYNC_DEQUE_BASE_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2013-2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> + +#include <boost/chrono/duration.hpp> +#include <boost/chrono/time_point.hpp> +#include <boost/chrono/system_clocks.hpp> +#include <boost/throw_exception.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ +namespace detail +{ + + template <class ValueType, class Queue> + class sync_deque_base + { + public: + typedef ValueType value_type; + typedef Queue underlying_queue_type; + typedef typename Queue::size_type size_type; + typedef queue_op_status op_status; + + typedef typename chrono::steady_clock clock; + typedef typename clock::duration duration; + typedef typename clock::time_point time_point; + + // Constructors/Assignment/Destructors + BOOST_THREAD_NO_COPYABLE(sync_deque_base) + inline sync_deque_base(); + //template <typename Range> + //inline explicit sync_deque(Range range); + inline ~sync_deque_base(); + + // Observers + inline bool empty() const; + inline bool full() const; + inline size_type size() const; + inline bool closed() const; + + // Modifiers + inline void close(); + + inline underlying_queue_type underlying_queue() { + lock_guard<mutex> lk(mtx_); + return boost::move(data_); + } + + protected: + mutable mutex mtx_; + condition_variable not_empty_; + underlying_queue_type data_; + bool closed_; + + inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT + { + return data_.empty(); + } + inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT + { + return data_.empty(); + } + + inline size_type size(lock_guard<mutex>& ) const BOOST_NOEXCEPT + { + return data_.size(); + } + inline bool closed(unique_lock<mutex>& lk) const; + inline bool closed(lock_guard<mutex>& lk) const; + + inline void throw_if_closed(unique_lock<mutex>&); + inline void throw_if_closed(lock_guard<mutex>&); + + inline void wait_until_not_empty(unique_lock<mutex>& lk); + inline bool wait_until_not_empty_or_closed(unique_lock<mutex>& lk); + inline queue_op_status wait_until_not_empty_until(unique_lock<mutex>& lk, time_point const&); + + inline void notify_not_empty_if_needed(unique_lock<mutex>& ) + { + not_empty_.notify_one(); + } + inline void notify_not_empty_if_needed(lock_guard<mutex>& ) + { + not_empty_.notify_one(); + } + + }; + + template <class ValueType, class Queue> + sync_deque_base<ValueType, Queue>::sync_deque_base() : + data_(), closed_(false) + { + BOOST_ASSERT(data_.empty()); + } + + template <class ValueType, class Queue> + sync_deque_base<ValueType, Queue>::~sync_deque_base() + { + } + + template <class ValueType, class Queue> + void sync_deque_base<ValueType, Queue>::close() + { + { + lock_guard<mutex> lk(mtx_); + closed_ = true; + } + not_empty_.notify_all(); + } + + template <class ValueType, class Queue> + bool sync_deque_base<ValueType, Queue>::closed() const + { + lock_guard<mutex> lk(mtx_); + return closed(lk); + } + template <class ValueType, class Queue> + bool sync_deque_base<ValueType, Queue>::closed(unique_lock<mutex>&) const + { + return closed_; + } + template <class ValueType, class Queue> + bool sync_deque_base<ValueType, Queue>::closed(lock_guard<mutex>&) const + { + return closed_; + } + + template <class ValueType, class Queue> + bool sync_deque_base<ValueType, Queue>::empty() const + { + lock_guard<mutex> lk(mtx_); + return empty(lk); + } + template <class ValueType, class Queue> + bool sync_deque_base<ValueType, Queue>::full() const + { + return false; + } + + template <class ValueType, class Queue> + typename sync_deque_base<ValueType, Queue>::size_type sync_deque_base<ValueType, Queue>::size() const + { + lock_guard<mutex> lk(mtx_); + return size(lk); + } + + template <class ValueType, class Queue> + void sync_deque_base<ValueType, Queue>::throw_if_closed(unique_lock<mutex>& lk) + { + if (closed(lk)) + { + BOOST_THROW_EXCEPTION( sync_deque_is_closed() ); + } + } + template <class ValueType, class Queue> + void sync_deque_base<ValueType, Queue>::throw_if_closed(lock_guard<mutex>& lk) + { + if (closed(lk)) + { + BOOST_THROW_EXCEPTION( sync_deque_is_closed() ); + } + } + + template <class ValueType, class Queue> + void sync_deque_base<ValueType, Queue>::wait_until_not_empty(unique_lock<mutex>& lk) + { + for (;;) + { + if (! empty(lk)) break; + throw_if_closed(lk); + not_empty_.wait(lk); + } + } + template <class ValueType, class Queue> + bool sync_deque_base<ValueType, Queue>::wait_until_not_empty_or_closed(unique_lock<mutex>& lk) + { + for (;;) + { + if (! empty(lk)) break; + if (closed(lk)) return true; + not_empty_.wait(lk); + } + return false; + } + + template <class ValueType, class Queue> + queue_op_status sync_deque_base<ValueType, Queue>::wait_until_not_empty_until(unique_lock<mutex>& lk, time_point const&tp) + { + for (;;) + { + if (! empty(lk)) return queue_op_status::success; + throw_if_closed(lk); + if (not_empty_.wait_until(lk, tp) == cv_status::timeout ) return queue_op_status::timeout; + } + } + + +} // detail +} // concurrent +} // boost + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/detail/sync_queue_base.hpp b/boost/thread/concurrent_queues/detail/sync_queue_base.hpp new file mode 100644 index 0000000000..653e273f8b --- /dev/null +++ b/boost/thread/concurrent_queues/detail/sync_queue_base.hpp @@ -0,0 +1,223 @@ +#ifndef BOOST_THREAD_CONCURRENT_QUEUES_DETAIL_SYNC_QUEUE_BASE_HPP +#define BOOST_THREAD_CONCURRENT_QUEUES_DETAIL_SYNC_QUEUE_BASE_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2013-2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> + +#include <boost/chrono/duration.hpp> +#include <boost/chrono/time_point.hpp> +#include <boost/chrono/system_clocks.hpp> +#include <boost/throw_exception.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ +namespace detail +{ + + template <class ValueType, class Queue> + class sync_queue_base + { + public: + typedef ValueType value_type; + typedef Queue underlying_queue_type; + typedef typename Queue::size_type size_type; + typedef queue_op_status op_status; + + typedef typename chrono::steady_clock clock; + typedef typename clock::duration duration; + typedef typename clock::time_point time_point; + + // Constructors/Assignment/Destructors + BOOST_THREAD_NO_COPYABLE(sync_queue_base) + inline sync_queue_base(); + //template <typename Range> + //inline explicit sync_queue(Range range); + inline ~sync_queue_base(); + + // Observers + inline bool empty() const; + inline bool full() const; + inline size_type size() const; + inline bool closed() const; + + // Modifiers + inline void close(); + + inline underlying_queue_type underlying_queue() { + lock_guard<mutex> lk(mtx_); + return boost::move(data_); + } + + protected: + mutable mutex mtx_; + condition_variable not_empty_; + underlying_queue_type data_; + bool closed_; + + inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT + { + return data_.empty(); + } + inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT + { + return data_.empty(); + } + + inline size_type size(lock_guard<mutex>& ) const BOOST_NOEXCEPT + { + return data_.size(); + } + inline bool closed(unique_lock<mutex>& lk) const; + inline bool closed(lock_guard<mutex>& lk) const; + + inline void throw_if_closed(unique_lock<mutex>&); + inline void throw_if_closed(lock_guard<mutex>&); + + inline void wait_until_not_empty(unique_lock<mutex>& lk); + inline bool wait_until_not_empty_or_closed(unique_lock<mutex>& lk); + inline queue_op_status wait_until_not_empty_until(unique_lock<mutex>& lk, time_point const&); + + inline void notify_not_empty_if_needed(unique_lock<mutex>& ) + { + not_empty_.notify_one(); + } + inline void notify_not_empty_if_needed(lock_guard<mutex>& ) + { + not_empty_.notify_one(); + } + + }; + + template <class ValueType, class Queue> + sync_queue_base<ValueType, Queue>::sync_queue_base() : + data_(), closed_(false) + { + BOOST_ASSERT(data_.empty()); + } + + template <class ValueType, class Queue> + sync_queue_base<ValueType, Queue>::~sync_queue_base() + { + } + + template <class ValueType, class Queue> + void sync_queue_base<ValueType, Queue>::close() + { + { + lock_guard<mutex> lk(mtx_); + closed_ = true; + } + not_empty_.notify_all(); + } + + template <class ValueType, class Queue> + bool sync_queue_base<ValueType, Queue>::closed() const + { + lock_guard<mutex> lk(mtx_); + return closed(lk); + } + template <class ValueType, class Queue> + bool sync_queue_base<ValueType, Queue>::closed(unique_lock<mutex>&) const + { + return closed_; + } + template <class ValueType, class Queue> + bool sync_queue_base<ValueType, Queue>::closed(lock_guard<mutex>&) const + { + return closed_; + } + + template <class ValueType, class Queue> + bool sync_queue_base<ValueType, Queue>::empty() const + { + lock_guard<mutex> lk(mtx_); + return empty(lk); + } + template <class ValueType, class Queue> + bool sync_queue_base<ValueType, Queue>::full() const + { + return false; + } + + template <class ValueType, class Queue> + typename sync_queue_base<ValueType, Queue>::size_type sync_queue_base<ValueType, Queue>::size() const + { + lock_guard<mutex> lk(mtx_); + return size(lk); + } + + template <class ValueType, class Queue> + void sync_queue_base<ValueType, Queue>::throw_if_closed(unique_lock<mutex>& lk) + { + if (closed(lk)) + { + BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + } + } + template <class ValueType, class Queue> + void sync_queue_base<ValueType, Queue>::throw_if_closed(lock_guard<mutex>& lk) + { + if (closed(lk)) + { + BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + } + } + + template <class ValueType, class Queue> + void sync_queue_base<ValueType, Queue>::wait_until_not_empty(unique_lock<mutex>& lk) + { + for (;;) + { + if (! empty(lk)) break; + throw_if_closed(lk); + not_empty_.wait(lk); + } + } + template <class ValueType, class Queue> + bool sync_queue_base<ValueType, Queue>::wait_until_not_empty_or_closed(unique_lock<mutex>& lk) + { + for (;;) + { + if (! empty(lk)) break; + if (closed(lk)) return true; + not_empty_.wait(lk); + } + return false; + } + + template <class ValueType, class Queue> + queue_op_status sync_queue_base<ValueType, Queue>::wait_until_not_empty_until(unique_lock<mutex>& lk, time_point const&tp) + { + for (;;) + { + if (! empty(lk)) return queue_op_status::success; + throw_if_closed(lk); + if (not_empty_.wait_until(lk, tp) == cv_status::timeout ) return queue_op_status::timeout; + } + } + + +} // detail +} // concurrent +} // boost + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/queue_adaptor.hpp b/boost/thread/concurrent_queues/queue_adaptor.hpp index c729276f99..f04e0354f7 100644 --- a/boost/thread/concurrent_queues/queue_adaptor.hpp +++ b/boost/thread/concurrent_queues/queue_adaptor.hpp @@ -27,12 +27,12 @@ namespace detail template <typename Queue> class queue_adaptor_copyable_only : - public boost::queue_base<typename Queue::value_type> + public boost::queue_base<typename Queue::value_type, typename Queue::size_type> { Queue queue; public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors queue_adaptor_copyable_only() {} @@ -46,29 +46,29 @@ namespace detail // Modifiers void close() { queue.close(); } - void push_back(const value_type& x) { queue.push_back(x); } + void push(const value_type& x) { queue.push(x); } - void pull_front(value_type& x) { queue.pull_front(x); }; - value_type pull_front() { return queue.pull_front(); } + void pull(value_type& x) { queue.pull(x); }; + value_type pull() { return queue.pull(); } - queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); } - queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); } + queue_op_status try_push(const value_type& x) { return queue.try_push(x); } + queue_op_status try_pull(value_type& x) { return queue.try_pull(x); } - queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); } - queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); } + queue_op_status nonblocking_push(const value_type& x) { return queue.nonblocking_push(x); } + queue_op_status nonblocking_pull(value_type& x) { return queue.nonblocking_pull(x); } - queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); } - queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); } + queue_op_status wait_push(const value_type& x) { return queue.wait_push(x); } + queue_op_status wait_pull(value_type& x) { return queue.wait_pull(x); } }; template <typename Queue> class queue_adaptor_movable_only : - public boost::queue_base<typename Queue::value_type> + public boost::queue_base<typename Queue::value_type, typename Queue::size_type> { Queue queue; public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors @@ -84,30 +84,30 @@ namespace detail void close() { queue.close(); } - void pull_front(value_type& x) { queue.pull_front(x); }; + void pull(value_type& x) { queue.pull(x); }; // enable_if is_nothrow_copy_movable<value_type> - value_type pull_front() { return queue.pull_front(); } + value_type pull() { return queue.pull(); } - queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); } + queue_op_status try_pull(value_type& x) { return queue.try_pull(x); } - queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); } + queue_op_status nonblocking_pull(value_type& x) { return queue.nonblocking_pull(x); } - queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); } + queue_op_status wait_pull(value_type& x) { return queue.wait_pull(x); } - void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); } - queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); } - queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); } - queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); } + void push(BOOST_THREAD_RV_REF(value_type) x) { queue.push(boost::move(x)); } + queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push(boost::move(x)); } + queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push(boost::move(x)); } + queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push(boost::move(x)); } }; template <typename Queue> class queue_adaptor_copyable_and_movable : - public boost::queue_base<typename Queue::value_type> + public boost::queue_base<typename Queue::value_type, typename Queue::size_type> { Queue queue; public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors @@ -123,31 +123,31 @@ namespace detail void close() { queue.close(); } - void push_back(const value_type& x) { queue.push_back(x); } + void push(const value_type& x) { queue.push(x); } - void pull_front(value_type& x) { queue.pull_front(x); }; + void pull(value_type& x) { queue.pull(x); }; // enable_if is_nothrow_copy_movable<value_type> - value_type pull_front() { return queue.pull_front(); } + value_type pull() { return queue.pull(); } - queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); } - queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); } + queue_op_status try_push(const value_type& x) { return queue.try_push(x); } + queue_op_status try_pull(value_type& x) { return queue.try_pull(x); } - queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); } - queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); } + queue_op_status nonblocking_push(const value_type& x) { return queue.nonblocking_push(x); } + queue_op_status nonblocking_pull(value_type& x) { return queue.nonblocking_pull(x); } - queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); } - queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); } + queue_op_status wait_push(const value_type& x) { return queue.wait_push(x); } + queue_op_status wait_pull(value_type& x) { return queue.wait_pull(x); } - void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); } - queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); } - queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); } - queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); } + void push(BOOST_THREAD_RV_REF(value_type) x) { queue.push(boost::move(x)); } + queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push(boost::move(x)); } + queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push(boost::move(x)); } + queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push(boost::move(x)); } }; template <class Q, class T, #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES -#if defined __GNUC__ +#if defined __GNUC__ && ! defined __clang__ #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__) bool Copyable = is_copy_constructible<T>::value, bool Movable = true @@ -195,7 +195,7 @@ namespace detail { public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors virtual ~queue_adaptor() {}; }; diff --git a/boost/thread/concurrent_queues/queue_base.hpp b/boost/thread/concurrent_queues/queue_base.hpp index 5ed14fd393..0d42839158 100755 --- a/boost/thread/concurrent_queues/queue_base.hpp +++ b/boost/thread/concurrent_queues/queue_base.hpp @@ -27,12 +27,12 @@ namespace concurrent namespace detail { - template <typename ValueType> + template <typename ValueType, class SizeType> class queue_base_copyable_only { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~queue_base_copyable_only() {}; @@ -46,28 +46,28 @@ namespace detail // Modifiers virtual void close() = 0; - virtual void push_back(const value_type& x) = 0; + virtual void push(const value_type& x) = 0; - virtual void pull_front(value_type&) = 0; - virtual value_type pull_front() = 0; + virtual void pull(value_type&) = 0; + virtual value_type pull() = 0; - virtual queue_op_status try_push_back(const value_type& x) = 0; - virtual queue_op_status try_pull_front(value_type&) = 0; + virtual queue_op_status try_push(const value_type& x) = 0; + virtual queue_op_status try_pull(value_type&) = 0; - virtual queue_op_status nonblocking_push_back(const value_type& x) = 0; - virtual queue_op_status nonblocking_pull_front(value_type&) = 0; + virtual queue_op_status nonblocking_push(const value_type& x) = 0; + virtual queue_op_status nonblocking_pull(value_type&) = 0; - virtual queue_op_status wait_push_back(const value_type& x) = 0; - virtual queue_op_status wait_pull_front(ValueType& elem) = 0; + virtual queue_op_status wait_push(const value_type& x) = 0; + virtual queue_op_status wait_pull(ValueType& elem) = 0; }; - template <typename ValueType> + template <typename ValueType, class SizeType> class queue_base_movable_only { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~queue_base_movable_only() {}; @@ -80,29 +80,29 @@ namespace detail // Modifiers virtual void close() = 0; - virtual void pull_front(value_type&) = 0; + virtual void pull(value_type&) = 0; // enable_if is_nothrow_movable<value_type> - virtual value_type pull_front() = 0; + virtual value_type pull() = 0; - virtual queue_op_status try_pull_front(value_type&) = 0; + virtual queue_op_status try_pull(value_type&) = 0; - virtual queue_op_status nonblocking_pull_front(value_type&) = 0; + virtual queue_op_status nonblocking_pull(value_type&) = 0; - virtual queue_op_status wait_pull_front(ValueType& elem) = 0; + virtual queue_op_status wait_pull(value_type& elem) = 0; - virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; - virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; - virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; - virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual void push(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) = 0; }; - template <typename ValueType> + template <typename ValueType, class SizeType> class queue_base_copyable_and_movable { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~queue_base_copyable_and_movable() {}; @@ -116,30 +116,30 @@ namespace detail // Modifiers virtual void close() = 0; - virtual void push_back(const value_type& x) = 0; + virtual void push(const value_type& x) = 0; - virtual void pull_front(value_type&) = 0; + virtual void pull(value_type&) = 0; // enable_if is_nothrow_copy_movable<value_type> - virtual value_type pull_front() = 0; + virtual value_type pull() = 0; - virtual queue_op_status try_push_back(const value_type& x) = 0; - virtual queue_op_status try_pull_front(value_type&) = 0; + virtual queue_op_status try_push(const value_type& x) = 0; + virtual queue_op_status try_pull(value_type&) = 0; - virtual queue_op_status nonblocking_push_back(const value_type& x) = 0; - virtual queue_op_status nonblocking_pull_front(value_type&) = 0; + virtual queue_op_status nonblocking_push(const value_type& x) = 0; + virtual queue_op_status nonblocking_pull(value_type&) = 0; - virtual queue_op_status wait_push_back(const value_type& x) = 0; - virtual queue_op_status wait_pull_front(ValueType& elem) = 0; + virtual queue_op_status wait_push(const value_type& x) = 0; + virtual queue_op_status wait_pull(value_type& elem) = 0; - virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; - virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; - virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; - virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual void push(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) = 0; }; - template <class T, + template <class T, class ST, #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES -#if defined __GNUC__ +#if defined __GNUC__ && ! defined __clang__ #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__) bool Copyable = is_copy_constructible<T>::value, bool Movable = true @@ -166,28 +166,28 @@ namespace detail > struct queue_base; - template <class T> - struct queue_base<T, true, true> { - typedef queue_base_copyable_and_movable<T> type; + template <class T, class ST> + struct queue_base<T, ST, true, true> { + typedef queue_base_copyable_and_movable<T, ST> type; }; - template <class T> - struct queue_base<T, true, false> { - typedef queue_base_copyable_only<T> type; + template <class T, class ST> + struct queue_base<T, ST, true, false> { + typedef queue_base_copyable_only<T, ST> type; }; - template <class T> - struct queue_base<T, false, true> { - typedef queue_base_movable_only<T> type; + template <class T, class ST> + struct queue_base<T, ST, false, true> { + typedef queue_base_movable_only<T, ST> type; }; } - template <typename ValueType> + template <typename ValueType, class SizeType=std::size_t> class queue_base : - public detail::queue_base<ValueType>::type + public detail::queue_base<ValueType, SizeType>::type { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~queue_base() {}; }; diff --git a/boost/thread/concurrent_queues/queue_op_status.hpp b/boost/thread/concurrent_queues/queue_op_status.hpp index 3a8f0d994d..197650d052 100644 --- a/boost/thread/concurrent_queues/queue_op_status.hpp +++ b/boost/thread/concurrent_queues/queue_op_status.hpp @@ -22,7 +22,7 @@ namespace concurrent { BOOST_SCOPED_ENUM_DECLARE_BEGIN(queue_op_status) - { success = 0, empty, full, closed, busy } + { success = 0, empty, full, closed, busy, timeout, not_ready } BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status) struct sync_queue_is_closed : std::exception diff --git a/boost/thread/concurrent_queues/queue_views.hpp b/boost/thread/concurrent_queues/queue_views.hpp index 1c06af8297..5a4512dd6e 100644 --- a/boost/thread/concurrent_queues/queue_views.hpp +++ b/boost/thread/concurrent_queues/queue_views.hpp @@ -43,27 +43,17 @@ namespace concurrent // Modifiers void close() { queue->close(); } - void push(const value_type& x) { queue->push_back(x); } + void push(const value_type& x) { queue->push(x); } - void pull(value_type& x) { queue->pull_back(x); } - // enable_if is_nothrow_copy_movable<value_type> - value_type pull() { return queue->pull_back(); } - - queue_op_status try_push(const value_type& x) { return queue->try_push_back(x); } - - queue_op_status try_pull(value_type& x) { return queue->try_pull_back(x); } - - queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_back(x); } - - queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_back(x); } + queue_op_status try_push(const value_type& x) { return queue->try_push(x); } - queue_op_status wait_push(const value_type& x) { return queue->wait_push_back(x); } - queue_op_status wait_pull(value_type& x) { return queue->wait_pull_back(x); } + queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push(x); } + queue_op_status wait_push(const value_type& x) { return queue->wait_push(x); } - void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_back(boost::move(x)); } - queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_back(boost::move(x)); } - queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_back(boost::move(x)); } - queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_back(boost::move(x)); } + void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push(boost::move(x)); } + queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push(boost::move(x)); } + queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push(boost::move(x)); } + queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push(boost::move(x)); } }; template <typename Queue> @@ -88,20 +78,20 @@ namespace concurrent void push(const value_type& x) { queue->push_front(x); } - void pull(value_type& x) { queue->pull_front(x); }; + void pull(value_type& x) { queue->pull(x); }; // enable_if is_nothrow_copy_movable<value_type> - value_type pull() { return queue->pull_front(); } + value_type pull() { return queue->pull(); } queue_op_status try_push(const value_type& x) { return queue->try_push_front(x); } - queue_op_status try_pull(value_type& x) { return queue->try_pull_front(x); } + queue_op_status try_pull(value_type& x) { return queue->try_pull(x); } queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_front(x); } - queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_front(x); } + queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull(x); } queue_op_status wait_push(const value_type& x) { return queue->wait_push_front(x); } - queue_op_status wait_pull(value_type& x) { return queue->wait_pull_front(x); } + queue_op_status wait_pull(value_type& x) { return queue->wait_pull(x); } void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_front(forward<value_type>(x)); } queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_front(forward<value_type>(x)); } queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_front(forward<value_type>(x)); } diff --git a/boost/thread/concurrent_queues/sync_bounded_queue.hpp b/boost/thread/concurrent_queues/sync_bounded_queue.hpp new file mode 100644 index 0000000000..e34fa56f37 --- /dev/null +++ b/boost/thread/concurrent_queues/sync_bounded_queue.hpp @@ -0,0 +1,725 @@ +#ifndef BOOST_THREAD_CONCURRENT_QUEUES_SYNC_BOUNDED_QUEUE_HPP +#define BOOST_THREAD_CONCURRENT_QUEUES_SYNC_BOUNDED_QUEUE_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2013-2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/throw_exception.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD +#include <boost/smart_ptr/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#endif +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ + template <typename ValueType> + class sync_bounded_queue + { + public: + typedef ValueType value_type; + typedef std::size_t size_type; + + // Constructors/Assignment/Destructors + BOOST_THREAD_NO_COPYABLE(sync_bounded_queue) + explicit sync_bounded_queue(size_type max_elems); + template <typename Range> + sync_bounded_queue(size_type max_elems, Range range); + ~sync_bounded_queue(); + + // Observers + inline bool empty() const; + inline bool full() const; + inline size_type capacity() const; + inline size_type size() const; + inline bool closed() const; + + // Modifiers + inline void close(); + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline void push(const value_type& x); + inline void push(BOOST_THREAD_RV_REF(value_type) x); + inline bool try_push(const value_type& x); + inline bool try_push(BOOST_THREAD_RV_REF(value_type) x); + inline bool try_push(no_block_tag, const value_type& x); + inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x); +#endif + inline void push_back(const value_type& x); + inline void push_back(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status try_push_back(const value_type& x); + inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status nonblocking_push_back(const value_type& x); + inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status wait_push_back(const value_type& x); + inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x); + + // Observers/Modifiers +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline void pull(value_type&); + // enable_if is_nothrow_copy_movable<value_type> + inline value_type pull(); + inline shared_ptr<ValueType> ptr_pull(); + inline bool try_pull(value_type&); + inline bool try_pull(no_block_tag,value_type&); + inline shared_ptr<ValueType> try_pull(); +#endif + inline void pull_front(value_type&); + // enable_if is_nothrow_copy_movable<value_type> + inline value_type pull_front(); + inline queue_op_status try_pull_front(value_type&); + inline queue_op_status nonblocking_pull_front(value_type&); + + inline queue_op_status wait_pull_front(ValueType& elem); + + private: + mutable mutex mtx_; + condition_variable not_empty_; + condition_variable not_full_; + size_type waiting_full_; + size_type waiting_empty_; + value_type* data_; + size_type in_; + size_type out_; + size_type capacity_; + bool closed_; + + inline size_type inc(size_type idx) const BOOST_NOEXCEPT + { + return (idx + 1) % capacity_; + } + + inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT + { + return in_ == out_; + } + inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT + { + return in_ == out_; + } + inline bool full(unique_lock<mutex>& ) const BOOST_NOEXCEPT + { + return (inc(in_) == out_); + } + inline bool full(lock_guard<mutex>& ) const BOOST_NOEXCEPT + { + return (inc(in_) == out_); + } + inline size_type capacity(lock_guard<mutex>& ) const BOOST_NOEXCEPT + { + return capacity_-1; + } + inline size_type size(lock_guard<mutex>& lk) const BOOST_NOEXCEPT + { + if (full(lk)) return capacity(lk); + return ((out_+capacity(lk)-in_) % capacity(lk)); + } + + inline void throw_if_closed(unique_lock<mutex>&); + inline bool closed(unique_lock<mutex>&) const; + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline bool try_pull(value_type& x, unique_lock<mutex>& lk); + inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk); + inline bool try_push(const value_type& x, unique_lock<mutex>& lk); + inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); +#endif + inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk); + inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk); + inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); + + inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk); + inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk); + inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); + + inline void wait_until_not_empty(unique_lock<mutex>& lk); + inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&); + inline size_type wait_until_not_full(unique_lock<mutex>& lk); + inline size_type wait_until_not_full(unique_lock<mutex>& lk, bool&); + + + inline void notify_not_empty_if_needed(unique_lock<mutex>& lk) + { + if (waiting_empty_ > 0) + { + --waiting_empty_; + lk.unlock(); + not_empty_.notify_one(); + } + } + inline void notify_not_full_if_needed(unique_lock<mutex>& lk) + { + if (waiting_full_ > 0) + { + --waiting_full_; + lk.unlock(); + not_full_.notify_one(); + } + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline void pull(value_type& elem, unique_lock<mutex>& lk) + { + elem = boost::move(data_[out_]); + out_ = inc(out_); + notify_not_full_if_needed(lk); + } + inline value_type pull(unique_lock<mutex>& lk) + { + value_type elem = boost::move(data_[out_]); + out_ = inc(out_); + notify_not_full_if_needed(lk); + return boost::move(elem); + } + inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk) + { + shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_[out_])); + out_ = inc(out_); + notify_not_full_if_needed(lk); + return res; + } +#endif + inline void pull_front(value_type& elem, unique_lock<mutex>& lk) + { + elem = boost::move(data_[out_]); + out_ = inc(out_); + notify_not_full_if_needed(lk); + } + inline value_type pull_front(unique_lock<mutex>& lk) + { + value_type elem = boost::move(data_[out_]); + out_ = inc(out_); + notify_not_full_if_needed(lk); + return boost::move(elem); + } + + inline void set_in(size_type in, unique_lock<mutex>& lk) + { + in_ = in; + notify_not_empty_if_needed(lk); + } + + inline void push_at(const value_type& elem, size_type in_p_1, unique_lock<mutex>& lk) + { + data_[in_] = elem; + set_in(in_p_1, lk); + } + + inline void push_at(BOOST_THREAD_RV_REF(value_type) elem, size_type in_p_1, unique_lock<mutex>& lk) + { + data_[in_] = boost::move(elem); + set_in(in_p_1, lk); + } + }; + + template <typename ValueType> + sync_bounded_queue<ValueType>::sync_bounded_queue(typename sync_bounded_queue<ValueType>::size_type max_elems) : + waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1), + closed_(false) + { + BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1"); + } + +// template <typename ValueType> +// template <typename Range> +// sync_bounded_queue<ValueType>::sync_bounded_queue(size_type max_elems, Range range) : +// waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1), +// closed_(false) +// { +// BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1"); +// BOOST_ASSERT_MSG(max_elems == size(range), "number of elements must match range's size"); +// try +// { +// typedef typename Range::iterator iterator_t; +// iterator_t first = boost::begin(range); +// iterator_t end = boost::end(range); +// size_type in = 0; +// for (iterator_t cur = first; cur != end; ++cur, ++in) +// { +// data_[in] = *cur; +// } +// set_in(in); +// } +// catch (...) +// { +// delete[] data_; +// } +// } + + template <typename ValueType> + sync_bounded_queue<ValueType>::~sync_bounded_queue() + { + delete[] data_; + } + + template <typename ValueType> + void sync_bounded_queue<ValueType>::close() + { + { + lock_guard<mutex> lk(mtx_); + closed_ = true; + } + not_empty_.notify_all(); + not_full_.notify_all(); + } + + template <typename ValueType> + bool sync_bounded_queue<ValueType>::closed() const + { + lock_guard<mutex> lk(mtx_); + return closed_; + } + template <typename ValueType> + bool sync_bounded_queue<ValueType>::closed(unique_lock<mutex>& ) const + { + return closed_; + } + + template <typename ValueType> + bool sync_bounded_queue<ValueType>::empty() const + { + lock_guard<mutex> lk(mtx_); + return empty(lk); + } + template <typename ValueType> + bool sync_bounded_queue<ValueType>::full() const + { + lock_guard<mutex> lk(mtx_); + return full(lk); + } + + template <typename ValueType> + typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::capacity() const + { + lock_guard<mutex> lk(mtx_); + return capacity(lk); + } + + template <typename ValueType> + typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::size() const + { + lock_guard<mutex> lk(mtx_); + return size(lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk) + { + if (empty(lk)) + { + throw_if_closed(lk); + return false; + } + pull(elem, lk); + return true; + } + template <typename ValueType> + shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull(unique_lock<mutex>& lk) + { + if (empty(lk)) + { + throw_if_closed(lk); + return shared_ptr<ValueType>(); + } + return ptr_pull(lk); + } + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return try_pull(elem, lk); + } +#endif + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk) + { + if (empty(lk)) + { + if (closed(lk)) return queue_op_status::closed; + return queue_op_status::empty; + } + pull_front(elem, lk); + return queue_op_status::success; + } + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return try_pull_front(elem, lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_pull(no_block_tag,ValueType& elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return false; + } + return try_pull(elem, lk); + } + template <typename ValueType> + boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull() + { + unique_lock<mutex> lk(mtx_); + return try_pull(lk); + } +#endif + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::nonblocking_pull_front(ValueType& elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return queue_op_status::busy; + } + return try_pull_front(elem, lk); + } + + template <typename ValueType> + void sync_bounded_queue<ValueType>::throw_if_closed(unique_lock<mutex>&) + { + if (closed_) + { + BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + } + } + + template <typename ValueType> + void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk) + { + for (;;) + { + if (out_ != in_) break; + throw_if_closed(lk); + ++waiting_empty_; + not_empty_.wait(lk); + } + } + template <typename ValueType> + void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed) + { + for (;;) + { + if (out_ != in_) break; + if (closed_) {closed=true; return;} + ++waiting_empty_; + not_empty_.wait(lk); + } + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + void sync_bounded_queue<ValueType>::pull(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + pull(elem, lk); + } +// template <typename ValueType> +// void sync_bounded_queue<ValueType>::pull(ValueType& elem, bool & closed) +// { +// unique_lock<mutex> lk(mtx_); +// wait_until_not_empty(lk, closed); +// if (closed) {return;} +// pull(elem, lk); +// } + + // enable if ValueType is nothrow movable + template <typename ValueType> + ValueType sync_bounded_queue<ValueType>::pull() + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + return pull(lk); + } + template <typename ValueType> + boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::ptr_pull() + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + return ptr_pull(lk); + } + +#endif + + template <typename ValueType> + void sync_bounded_queue<ValueType>::pull_front(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + pull_front(elem, lk); + } + + // enable if ValueType is nothrow movable + template <typename ValueType> + ValueType sync_bounded_queue<ValueType>::pull_front() + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + return pull_front(lk); + } + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk) + { + if (empty(lk) && closed(lk)) {return queue_op_status::closed;} + wait_until_not_empty(lk); + pull_front(elem, lk); + return queue_op_status::success; + } + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return wait_pull_front(elem, lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk) + { + throw_if_closed(lk); + size_type in_p_1 = inc(in_); + if (in_p_1 == out_) // full() + { + return false; + } + push_at(elem, in_p_1, lk); + return true; + } + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return try_push(elem, lk); + } + +#endif + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk) + { + if (closed(lk)) return queue_op_status::closed; + size_type in_p_1 = inc(in_); + if (in_p_1 == out_) // full() + { + return queue_op_status::full; + } + push_at(elem, in_p_1, lk); + return queue_op_status::success; + } + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return try_push_back(elem, lk); + } + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk) + { + if (closed(lk)) return queue_op_status::closed; + push_at(elem, wait_until_not_full(lk), lk); + return queue_op_status::success; + } + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return wait_push_back(elem, lk); + } + + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_push(no_block_tag, const ValueType& elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) return false; + return try_push(elem, lk); + } +#endif + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) return queue_op_status::busy; + return try_push_back(elem, lk); + } + + template <typename ValueType> + typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::wait_until_not_full(unique_lock<mutex>& lk) + { + for (;;) + { + throw_if_closed(lk); + size_type in_p_1 = inc(in_); + if (in_p_1 != out_) // ! full() + { + return in_p_1; + } + ++waiting_full_; + not_full_.wait(lk); + } + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + void sync_bounded_queue<ValueType>::push(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + push_at(elem, wait_until_not_full(lk), lk); + } +#endif + template <typename ValueType> + void sync_bounded_queue<ValueType>::push_back(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + push_at(elem, wait_until_not_full(lk), lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + throw_if_closed(lk); + size_type in_p_1 = inc(in_); + if (in_p_1 == out_) // full() + { + return false; + } + push_at(boost::move(elem), in_p_1, lk); + return true; + } + + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + return try_push(boost::move(elem), lk); + } +#endif + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + if (closed(lk)) return queue_op_status::closed; + size_type in_p_1 = inc(in_); + if (in_p_1 == out_) // full() + { + return queue_op_status::full; + } + push_at(boost::move(elem), in_p_1, lk); + return queue_op_status::success; + } + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + return try_push_back(boost::move(elem), lk); + } + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + if (closed(lk)) return queue_op_status::closed; + push_at(boost::move(elem), wait_until_not_full(lk), lk); + return queue_op_status::success; + } + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + return try_push_back(boost::move(elem), lk); + } + + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return false; + } + return try_push(boost::move(elem), lk); + } +#endif + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return queue_op_status::busy; + } + return try_push_back(boost::move(elem), lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + void sync_bounded_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + push_at(boost::move(elem), wait_until_not_full(lk), lk); + } +#endif + template <typename ValueType> + void sync_bounded_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + push_at(boost::move(elem), wait_until_not_full(lk), lk); + } + + template <typename ValueType> + sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem) + { + sbq.push_back(boost::move(elem)); + return sbq; + } + + template <typename ValueType> + sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem) + { + sbq.push_back(elem); + return sbq; + } + + template <typename ValueType> + sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem) + { + sbq.pull_front(elem); + return sbq; + } +} +using concurrent::sync_bounded_queue; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/sync_deque.hpp b/boost/thread/concurrent_queues/sync_deque.hpp new file mode 100644 index 0000000000..c84dae022a --- /dev/null +++ b/boost/thread/concurrent_queues/sync_deque.hpp @@ -0,0 +1,327 @@ +#ifndef BOOST_THREAD_CONCURRENT_QUEUES_SYNC_DEQUE_HPP +#define BOOST_THREAD_CONCURRENT_QUEUES_SYNC_DEQUE_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2013-2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/concurrent_queues/detail/sync_queue_base.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/thread/csbl/devector.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/mutex.hpp> + +#include <boost/throw_exception.hpp> +#include <boost/smart_ptr/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ + template <class ValueType, class Container = csbl::devector<ValueType> > + class sync_deque + : public detail::sync_queue_base<ValueType, Container > + { + typedef detail::sync_queue_base<ValueType, Container > super; + + public: + typedef ValueType value_type; + //typedef typename super::value_type value_type; // fixme + typedef typename super::underlying_queue_type underlying_queue_type; + typedef typename super::size_type size_type; + typedef typename super::op_status op_status; + + // Constructors/Assignment/Destructors + BOOST_THREAD_NO_COPYABLE(sync_deque) + inline sync_deque(); + //template <typename Range> + //inline explicit sync_deque(Range range); + inline ~sync_deque(); + + // Modifiers + inline void push_back(const value_type& x); + inline queue_op_status try_push_back(const value_type& x); + inline queue_op_status nonblocking_push_back(const value_type& x); + inline queue_op_status wait_push_back(const value_type& x); + inline void push_back(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x); + + // Observers/Modifiers + inline void pull_front(value_type&); + // enable_if is_nothrow_copy_movable<value_type> + inline value_type pull_front(); + + inline queue_op_status try_pull_front(value_type&); + inline queue_op_status nonblocking_pull_front(value_type&); + inline queue_op_status wait_pull_front(ValueType& elem); + + private: + + inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk); + inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk); + inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk); + inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk); + inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); + inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); + + inline void pull_front(value_type& elem, unique_lock<mutex>& ) + { + elem = boost::move(super::data_.front()); + super::data_.pop_front(); + } + inline value_type pull_front(unique_lock<mutex>& ) + { + value_type e = boost::move(super::data_.front()); + super::data_.pop_front(); + return boost::move(e); + } + + inline void push_back(const value_type& elem, unique_lock<mutex>& lk) + { + super::data_.push_back(elem); + super::notify_not_empty_if_needed(lk); + } + + inline void push_back(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk) + { + super::data_.push_back(boost::move(elem)); + super::notify_not_empty_if_needed(lk); + } + }; + + template <class ValueType, class Container> + sync_deque<ValueType, Container>::sync_deque() : + super() + { + } + +// template <class ValueType, class Container> +// template <class Range> +// explicit sync_deque<ValueType, Container>::sync_deque(Range range) : +// data_(), closed_(false) +// { +// try +// { +// typedef typename Range::iterator iterator_t; +// iterator_t first = boost::begin(range); +// iterator_t end = boost::end(range); +// for (iterator_t cur = first; cur != end; ++cur) +// { +// data_.push(boost::move(*cur));; +// } +// notify_not_empty_if_needed(lk); +// } +// catch (...) +// { +// delete[] data_; +// } +// } + + template <class ValueType, class Container> + sync_deque<ValueType, Container>::~sync_deque() + { + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk) + { + if (super::empty(lk)) + { + if (super::closed(lk)) return queue_op_status::closed; + return queue_op_status::empty; + } + pull_front(elem, lk); + return queue_op_status::success; + } + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk) + { + if (super::empty(lk)) + { + if (super::closed(lk)) return queue_op_status::closed; + } + bool has_been_closed = super::wait_until_not_empty_or_closed(lk); + if (has_been_closed) return queue_op_status::closed; + pull_front(elem, lk); + return queue_op_status::success; + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::try_pull_front(ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_); + return try_pull_front(elem, lk); + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::wait_pull_front(ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_); + return wait_pull_front(elem, lk); + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::nonblocking_pull_front(ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return queue_op_status::busy; + } + return try_pull_front(elem, lk); + } + + template <class ValueType, class Container> + void sync_deque<ValueType, Container>::pull_front(ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_); + super::wait_until_not_empty(lk); + pull_front(elem, lk); + } + + // enable if ValueType is nothrow movable + template <class ValueType, class Container> + ValueType sync_deque<ValueType, Container>::pull_front() + { + unique_lock<mutex> lk(super::mtx_); + super::wait_until_not_empty(lk); + return pull_front(lk); + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk) + { + if (super::closed(lk)) return queue_op_status::closed; + push_back(elem, lk); + return queue_op_status::success; + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::try_push_back(const ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_); + return try_push_back(elem, lk); + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk) + { + if (super::closed(lk)) return queue_op_status::closed; + push_back(elem, lk); + return queue_op_status::success; + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::wait_push_back(const ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_); + return wait_push_back(elem, lk); + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::nonblocking_push_back(const ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_, try_to_lock); + if (!lk.owns_lock()) return queue_op_status::busy; + return try_push_back(elem, lk); + } + + template <class ValueType, class Container> + void sync_deque<ValueType, Container>::push_back(const ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_); + super::throw_if_closed(lk); + push_back(elem, lk); + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + if (super::closed(lk)) return queue_op_status::closed; + push_back(boost::move(elem), lk); + return queue_op_status::success; + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(super::mtx_); + return try_push_back(boost::move(elem), lk); + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + if (super::closed(lk)) return queue_op_status::closed; + push_back(boost::move(elem), lk); + return queue_op_status::success; + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(super::mtx_); + return wait_push_back(boost::move(elem), lk); + } + + template <class ValueType, class Container> + queue_op_status sync_deque<ValueType, Container>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(super::mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return queue_op_status::busy; + } + return try_push_back(boost::move(elem), lk); + } + + template <class ValueType, class Container> + void sync_deque<ValueType, Container>::push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(super::mtx_); + super::throw_if_closed(lk); + push_back(boost::move(elem), lk); + } + + template <class ValueType, class Container> + sync_deque<ValueType, Container>& operator<<(sync_deque<ValueType, Container>& sbq, BOOST_THREAD_RV_REF(ValueType) elem) + { + sbq.push_back(boost::move(elem)); + return sbq; + } + + template <class ValueType, class Container> + sync_deque<ValueType, Container>& operator<<(sync_deque<ValueType, Container>& sbq, ValueType const&elem) + { + sbq.push_back(elem); + return sbq; + } + + template <class ValueType, class Container> + sync_deque<ValueType, Container>& operator>>(sync_deque<ValueType, Container>& sbq, ValueType &elem) + { + sbq.pull_front(elem); + return sbq; + } + +} +using concurrent::sync_deque; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/sync_priority_queue.hpp b/boost/thread/concurrent_queues/sync_priority_queue.hpp new file mode 100644 index 0000000000..d604faa742 --- /dev/null +++ b/boost/thread/concurrent_queues/sync_priority_queue.hpp @@ -0,0 +1,369 @@ +// Copyright (C) 2014 Ian Forbed +// Copyright (C) 2014 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) +// + +#ifndef BOOST_THREAD_SYNC_PRIORITY_QUEUE +#define BOOST_THREAD_SYNC_PRIORITY_QUEUE + +#include <boost/thread/detail/config.hpp> + +#include <boost/thread/concurrent_queues/detail/sync_queue_base.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/thread/csbl/vector.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/mutex.hpp> + +#include <boost/atomic.hpp> +#include <boost/chrono/duration.hpp> +#include <boost/chrono/time_point.hpp> + +#include <exception> +#include <queue> +#include <utility> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace detail { + + template < + class Type, + class Container = csbl::vector<Type>, + class Compare = std::less<Type> + > + class priority_queue + { + private: + Container _elements; + Compare _compare; + public: + typedef Type value_type; + typedef typename Container::size_type size_type; + + explicit priority_queue(const Compare& compare = Compare()) + : _elements(), _compare(compare) + { } + + size_type size() const + { + return _elements.size(); + } + + bool empty() const + { + return _elements.empty(); + } + + void push(Type const& element) + { + _elements.push_back(element); + std::push_heap(_elements.begin(), _elements.end(), _compare); + } + void push(BOOST_RV_REF(Type) element) + { + _elements.push_back(boost::move(element)); + std::push_heap(_elements.begin(), _elements.end(), _compare); + } + + void pop() + { + std::pop_heap(_elements.begin(), _elements.end(), _compare); + _elements.pop_back(); + } + Type pull() + { + Type result = boost::move(_elements.front()); + pop(); + return boost::move(result); + } + + Type const& top() + { + return _elements.front(); + } + }; +} + +namespace concurrent +{ + template <class ValueType, + class Container = csbl::vector<ValueType>, + class Compare = std::less<typename Container::value_type> > + class sync_priority_queue + : public detail::sync_queue_base<ValueType, boost::detail::priority_queue<ValueType,Container,Compare> > + { + typedef detail::sync_queue_base<ValueType, boost::detail::priority_queue<ValueType,Container,Compare> > super; + + public: + typedef ValueType value_type; + //typedef typename super::value_type value_type; // fixme + typedef typename super::underlying_queue_type underlying_queue_type; + typedef typename super::size_type size_type; + typedef typename super::op_status op_status; + + typedef chrono::steady_clock clock; + protected: + + public: + sync_priority_queue() {} + + ~sync_priority_queue() + { + if(!super::closed()) + { + super::close(); + } + } + + void push(const ValueType& elem); + void push(BOOST_THREAD_RV_REF(ValueType) elem); + + queue_op_status try_push(const ValueType& elem); + queue_op_status try_push(BOOST_THREAD_RV_REF(ValueType) elem); + + ValueType pull(); + + void pull(ValueType&); + + queue_op_status pull_until(const clock::time_point&, ValueType&); + queue_op_status pull_for(const clock::duration&, ValueType&); + + queue_op_status try_pull(ValueType& elem); + queue_op_status wait_pull(ValueType& elem); + queue_op_status nonblocking_pull(ValueType&); + + private: + void push(unique_lock<mutex>&, const ValueType& elem); + void push(lock_guard<mutex>&, const ValueType& elem); + void push(unique_lock<mutex>&, BOOST_THREAD_RV_REF(ValueType) elem); + void push(lock_guard<mutex>&, BOOST_THREAD_RV_REF(ValueType) elem); + + queue_op_status try_push(unique_lock<mutex>&, const ValueType& elem); + queue_op_status try_push(unique_lock<mutex>&, BOOST_THREAD_RV_REF(ValueType) elem); + + ValueType pull(unique_lock<mutex>&); + ValueType pull(lock_guard<mutex>&); + + void pull(unique_lock<mutex>&, ValueType&); + void pull(lock_guard<mutex>&, ValueType&); + + queue_op_status try_pull(lock_guard<mutex>& lk, ValueType& elem); + queue_op_status try_pull(unique_lock<mutex>& lk, ValueType& elem); + + queue_op_status wait_pull(unique_lock<mutex>& lk, ValueType& elem); + + queue_op_status nonblocking_pull(unique_lock<mutex>& lk, ValueType&); + + sync_priority_queue(const sync_priority_queue&); + sync_priority_queue& operator= (const sync_priority_queue&); + sync_priority_queue(BOOST_THREAD_RV_REF(sync_priority_queue)); + sync_priority_queue& operator= (BOOST_THREAD_RV_REF(sync_priority_queue)); + }; //end class + + + ////////////////////// + template <class T, class Container,class Cmp> + void sync_priority_queue<T,Container,Cmp>::push(unique_lock<mutex>& lk, const T& elem) + { + super::throw_if_closed(lk); + super::data_.push(elem); + super::notify_not_empty_if_needed(lk); + } + template <class T, class Container,class Cmp> + void sync_priority_queue<T,Container,Cmp>::push(lock_guard<mutex>& lk, const T& elem) + { + super::throw_if_closed(lk); + super::data_.push(elem); + super::notify_not_empty_if_needed(lk); + } + template <class T, class Container,class Cmp> + void sync_priority_queue<T,Container,Cmp>::push(const T& elem) + { + lock_guard<mutex> lk(super::mtx_); + push(lk, elem); + } + + ////////////////////// + template <class T, class Container,class Cmp> + void sync_priority_queue<T,Container,Cmp>::push(unique_lock<mutex>& lk, BOOST_THREAD_RV_REF(T) elem) + { + super::throw_if_closed(lk); + super::data_.push(boost::move(elem)); + super::notify_not_empty_if_needed(lk); + } + template <class T, class Container,class Cmp> + void sync_priority_queue<T,Container,Cmp>::push(lock_guard<mutex>& lk, BOOST_THREAD_RV_REF(T) elem) + { + super::throw_if_closed(lk); + super::data_.push(boost::move(elem)); + super::notify_not_empty_if_needed(lk); + } + template <class T, class Container,class Cmp> + void sync_priority_queue<T,Container,Cmp>::push(BOOST_THREAD_RV_REF(T) elem) + { + lock_guard<mutex> lk(super::mtx_); + push(lk, boost::move(elem)); + } + + ////////////////////// + template <class T, class Container,class Cmp> + queue_op_status sync_priority_queue<T,Container,Cmp>::try_push(const T& elem) + { + lock_guard<mutex> lk(super::mtx_); + if (super::closed(lk)) return queue_op_status::closed; + push(lk, elem); + return queue_op_status::success; + } + + ////////////////////// + template <class T, class Container,class Cmp> + queue_op_status sync_priority_queue<T,Container,Cmp>::try_push(BOOST_THREAD_RV_REF(T) elem) + { + lock_guard<mutex> lk(super::mtx_); + if (super::closed(lk)) return queue_op_status::closed; + push(lk, boost::move(elem)); + + return queue_op_status::success; + } + + ////////////////////// + template <class T,class Container, class Cmp> + T sync_priority_queue<T,Container,Cmp>::pull(unique_lock<mutex>&) + { + return super::data_.pull(); + } + template <class T,class Container, class Cmp> + T sync_priority_queue<T,Container,Cmp>::pull(lock_guard<mutex>&) + { + return super::data_.pull(); + } + + template <class T,class Container, class Cmp> + T sync_priority_queue<T,Container,Cmp>::pull() + { + unique_lock<mutex> lk(super::mtx_); + super::wait_until_not_empty(lk); + return pull(lk); + } + + ////////////////////// + template <class T,class Container, class Cmp> + void sync_priority_queue<T,Container,Cmp>::pull(unique_lock<mutex>&, T& elem) + { + elem = super::data_.pull(); + } + template <class T,class Container, class Cmp> + void sync_priority_queue<T,Container,Cmp>::pull(lock_guard<mutex>&, T& elem) + { + elem = super::data_.pull(); + } + + template <class T,class Container, class Cmp> + void sync_priority_queue<T,Container,Cmp>::pull(T& elem) + { + unique_lock<mutex> lk(super::mtx_); + super::wait_until_not_empty(lk); + pull(lk, elem); + } + + ////////////////////// + template <class T, class Cont,class Cmp> + queue_op_status + sync_priority_queue<T,Cont,Cmp>::pull_until(const clock::time_point& tp, T& elem) + { + unique_lock<mutex> lk(super::mtx_); + if (queue_op_status::timeout == super::wait_until_not_empty_until(lk, tp)) + return queue_op_status::timeout; + pull(lk, elem); + return queue_op_status::success; + } + + ////////////////////// + template <class T, class Cont,class Cmp> + queue_op_status + sync_priority_queue<T,Cont,Cmp>::pull_for(const clock::duration& dura, T& elem) + { + return pull_until(clock::now() + dura, elem); + } + + ////////////////////// + template <class T, class Container,class Cmp> + queue_op_status + sync_priority_queue<T,Container,Cmp>::try_pull(unique_lock<mutex>& lk, T& elem) + { + if (super::empty(lk)) + { + if (super::closed(lk)) return queue_op_status::closed; + return queue_op_status::empty; + } + pull(lk, elem); + return queue_op_status::success; + } + + template <class T, class Container,class Cmp> + queue_op_status + sync_priority_queue<T,Container,Cmp>::try_pull(lock_guard<mutex>& lk, T& elem) + { + if (super::empty(lk)) + { + if (super::closed(lk)) return queue_op_status::closed; + return queue_op_status::empty; + } + pull(lk, elem); + return queue_op_status::success; + } + + template <class T, class Container,class Cmp> + queue_op_status + sync_priority_queue<T,Container,Cmp>::try_pull(T& elem) + { + lock_guard<mutex> lk(super::mtx_); + return try_pull(lk, elem); + } + + ////////////////////// + template <class T,class Container, class Cmp> + queue_op_status sync_priority_queue<T,Container,Cmp>::wait_pull(unique_lock<mutex>& lk, T& elem) + { + if (super::empty(lk)) + { + if (super::closed(lk)) return queue_op_status::closed; + } + bool has_been_closed = super::wait_until_not_empty_or_closed(lk); + if (has_been_closed) return queue_op_status::closed; + pull(lk, elem); + return queue_op_status::success; + } + + template <class T,class Container, class Cmp> + queue_op_status sync_priority_queue<T,Container,Cmp>::wait_pull(T& elem) + { + unique_lock<mutex> lk(super::mtx_); + return wait_pull(lk, elem); + } + + ////////////////////// + + template <class T,class Container, class Cmp> + queue_op_status sync_priority_queue<T,Container,Cmp>::nonblocking_pull(T& elem) + { + unique_lock<mutex> lk(super::mtx_, try_to_lock); + if (!lk.owns_lock()) return queue_op_status::busy; + return try_pull(lk, elem); + } + + + +} //end concurrent namespace + +using concurrent::sync_priority_queue; + +} //end boost namespace +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/sync_queue.hpp b/boost/thread/concurrent_queues/sync_queue.hpp new file mode 100644 index 0000000000..7183c9cad8 --- /dev/null +++ b/boost/thread/concurrent_queues/sync_queue.hpp @@ -0,0 +1,328 @@ +#ifndef BOOST_THREAD_CONCURRENT_QUEUES_SYNC_QUEUE_HPP +#define BOOST_THREAD_CONCURRENT_QUEUES_SYNC_QUEUE_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2013-2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/concurrent_queues/detail/sync_queue_base.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/thread/csbl/devector.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/mutex.hpp> + +#include <boost/throw_exception.hpp> +#include <boost/smart_ptr/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ + template <class ValueType, class Container = csbl::devector<ValueType> > + class sync_queue + : public detail::sync_queue_base<ValueType, Container > + { + typedef detail::sync_queue_base<ValueType, Container > super; + + public: + typedef ValueType value_type; + //typedef typename super::value_type value_type; // fixme + typedef typename super::underlying_queue_type underlying_queue_type; + typedef typename super::size_type size_type; + typedef typename super::op_status op_status; + + // Constructors/Assignment/Destructors + BOOST_THREAD_NO_COPYABLE(sync_queue) + inline sync_queue(); + //template <class Range> + //inline explicit sync_queue(Range range); + inline ~sync_queue(); + + // Modifiers + + inline void push(const value_type& x); + inline queue_op_status try_push(const value_type& x); + inline queue_op_status nonblocking_push(const value_type& x); + inline queue_op_status wait_push(const value_type& x); + inline void push(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x); + + // Observers/Modifiers + inline void pull(value_type&); + // enable_if is_nothrow_copy_movable<value_type> + inline value_type pull(); + + inline queue_op_status try_pull(value_type&); + inline queue_op_status nonblocking_pull(value_type&); + inline queue_op_status wait_pull(ValueType& elem); + + private: + + inline queue_op_status try_pull(value_type& x, unique_lock<mutex>& lk); + inline queue_op_status wait_pull(value_type& x, unique_lock<mutex>& lk); + inline queue_op_status try_push(const value_type& x, unique_lock<mutex>& lk); + inline queue_op_status wait_push(const value_type& x, unique_lock<mutex>& lk); + inline queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); + inline queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); + + inline void pull(value_type& elem, unique_lock<mutex>& ) + { + elem = boost::move(super::data_.front()); + super::data_.pop_front(); + } + inline value_type pull(unique_lock<mutex>& ) + { + value_type e = boost::move(super::data_.front()); + super::data_.pop_front(); + return boost::move(e); + } + + inline void push(const value_type& elem, unique_lock<mutex>& lk) + { + super::data_.push_back(elem); + super::notify_not_empty_if_needed(lk); + } + + inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk) + { + super::data_.push_back(boost::move(elem)); + super::notify_not_empty_if_needed(lk); + } + }; + + template <class ValueType, class Container> + sync_queue<ValueType, Container>::sync_queue() : + super() + { + } + +// template <class ValueType, class Container> +// template <class Range> +// explicit sync_queue<ValueType, Container>::sync_queue(Range range) : +// data_(), closed_(false) +// { +// try +// { +// typedef typename Range::iterator iterator_t; +// iterator_t first = boost::begin(range); +// iterator_t end = boost::end(range); +// for (iterator_t cur = first; cur != end; ++cur) +// { +// data_.push(boost::move(*cur));; +// } +// notify_not_empty_if_needed(lk); +// } +// catch (...) +// { +// delete[] data_; +// } +// } + + template <class ValueType, class Container> + sync_queue<ValueType, Container>::~sync_queue() + { + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::try_pull(ValueType& elem, unique_lock<mutex>& lk) + { + if (super::empty(lk)) + { + if (super::closed(lk)) return queue_op_status::closed; + return queue_op_status::empty; + } + pull(elem, lk); + return queue_op_status::success; + } + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::wait_pull(ValueType& elem, unique_lock<mutex>& lk) + { + if (super::empty(lk)) + { + if (super::closed(lk)) return queue_op_status::closed; + } + bool has_been_closed = super::wait_until_not_empty_or_closed(lk); + if (has_been_closed) return queue_op_status::closed; + pull(elem, lk); + return queue_op_status::success; + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::try_pull(ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_); + return try_pull(elem, lk); + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::wait_pull(ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_); + return wait_pull(elem, lk); + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::nonblocking_pull(ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return queue_op_status::busy; + } + return try_pull(elem, lk); + } + + template <class ValueType, class Container> + void sync_queue<ValueType, Container>::pull(ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_); + super::wait_until_not_empty(lk); + pull(elem, lk); + } + + // enable if ValueType is nothrow movable + template <class ValueType, class Container> + ValueType sync_queue<ValueType, Container>::pull() + { + unique_lock<mutex> lk(super::mtx_); + super::wait_until_not_empty(lk); + return pull(lk); + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::try_push(const ValueType& elem, unique_lock<mutex>& lk) + { + if (super::closed(lk)) return queue_op_status::closed; + push(elem, lk); + return queue_op_status::success; + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::try_push(const ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_); + return try_push(elem, lk); + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::wait_push(const ValueType& elem, unique_lock<mutex>& lk) + { + if (super::closed(lk)) return queue_op_status::closed; + push(elem, lk); + return queue_op_status::success; + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::wait_push(const ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_); + return wait_push(elem, lk); + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::nonblocking_push(const ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_, try_to_lock); + if (!lk.owns_lock()) return queue_op_status::busy; + return try_push(elem, lk); + } + + template <class ValueType, class Container> + void sync_queue<ValueType, Container>::push(const ValueType& elem) + { + unique_lock<mutex> lk(super::mtx_); + super::throw_if_closed(lk); + push(elem, lk); + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + if (super::closed(lk)) return queue_op_status::closed; + push(boost::move(elem), lk); + return queue_op_status::success; + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::try_push(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(super::mtx_); + return try_push(boost::move(elem), lk); + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::wait_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + if (super::closed(lk)) return queue_op_status::closed; + push(boost::move(elem), lk); + return queue_op_status::success; + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::wait_push(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(super::mtx_); + return wait_push(boost::move(elem), lk); + } + + template <class ValueType, class Container> + queue_op_status sync_queue<ValueType, Container>::nonblocking_push(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(super::mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return queue_op_status::busy; + } + return try_push(boost::move(elem), lk); + } + + template <class ValueType, class Container> + void sync_queue<ValueType, Container>::push(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(super::mtx_); + super::throw_if_closed(lk); + push(boost::move(elem), lk); + } + + template <class ValueType, class Container> + sync_queue<ValueType, Container>& operator<<(sync_queue<ValueType, Container>& sbq, BOOST_THREAD_RV_REF(ValueType) elem) + { + sbq.push(boost::move(elem)); + return sbq; + } + + template <class ValueType, class Container> + sync_queue<ValueType, Container>& operator<<(sync_queue<ValueType, Container>& sbq, ValueType const&elem) + { + sbq.push(elem); + return sbq; + } + + template <class ValueType, class Container> + sync_queue<ValueType, Container>& operator>>(sync_queue<ValueType, Container>& sbq, ValueType &elem) + { + sbq.pull(elem); + return sbq; + } + +} +using concurrent::sync_queue; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/sync_timed_queue.hpp b/boost/thread/concurrent_queues/sync_timed_queue.hpp new file mode 100644 index 0000000000..8f24f43ecd --- /dev/null +++ b/boost/thread/concurrent_queues/sync_timed_queue.hpp @@ -0,0 +1,466 @@ +// Copyright (C) 2014 Ian Forbed +// Copyright (C) 2014 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) +// + +#ifndef BOOST_THREAD_SYNC_TIMED_QUEUE_HPP +#define BOOST_THREAD_SYNC_TIMED_QUEUE_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/thread/concurrent_queues/sync_priority_queue.hpp> +#include <boost/chrono/duration.hpp> +#include <boost/chrono/time_point.hpp> +#include <boost/chrono/system_clocks.hpp> +#include <boost/chrono/chrono_io.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ +namespace detail +{ + template <class T, class Clock = chrono::steady_clock> + struct scheduled_type + { + typedef T value_type; + typedef Clock clock; + typedef typename clock::time_point time_point; + T data; + time_point time; + + BOOST_THREAD_COPYABLE_AND_MOVABLE(scheduled_type) + + scheduled_type(T const& pdata, time_point tp) : data(pdata), time(tp) {} + scheduled_type(BOOST_THREAD_RV_REF(T) pdata, time_point tp) : data(boost::move(pdata)), time(tp) {} + + scheduled_type(scheduled_type const& other) : data(other.data), time(other.time) {} + scheduled_type& operator=(BOOST_THREAD_COPY_ASSIGN_REF(scheduled_type) other) { + data = other.data; + time = other.time; + return *this; + } + + scheduled_type(BOOST_THREAD_RV_REF(scheduled_type) other) : data(boost::move(other.data)), time(other.time) {} + scheduled_type& operator=(BOOST_THREAD_RV_REF(scheduled_type) other) { + data = boost::move(other.data); + time = other.time; + return *this; + } + + bool time_not_reached() const + { + return time > clock::now(); + } + + bool operator <(const scheduled_type<T> other) const + { + return this->time > other.time; + } + }; //end struct + +} //end detail namespace + + template <class T, class Clock = chrono::steady_clock> + class sync_timed_queue + : private sync_priority_queue<detail::scheduled_type<T, Clock> > + { + typedef detail::scheduled_type<T> stype; + typedef sync_priority_queue<stype> super; + public: + typedef T value_type; + typedef Clock clock; + typedef typename clock::duration duration; + typedef typename clock::time_point time_point; + typedef typename super::underlying_queue_type underlying_queue_type; + typedef typename super::size_type size_type; + typedef typename super::op_status op_status; + + sync_timed_queue() : super() {}; + ~sync_timed_queue() {} + + using super::size; + using super::empty; + using super::full; + using super::close; + using super::closed; + + T pull(); + void pull(T& elem); + + template <class Duration> + queue_op_status pull_until(chrono::time_point<clock,Duration> const& tp, T& elem); + template <class Rep, class Period> + queue_op_status pull_for(chrono::duration<Rep,Period> const& dura, T& elem); + + queue_op_status try_pull(T& elem); + queue_op_status wait_pull(T& elem); + queue_op_status nonblocking_pull(T& elem); + + template <class Duration> + void push(const T& elem, chrono::time_point<clock,Duration> const& tp); + template <class Rep, class Period> + void push(const T& elem, chrono::duration<Rep,Period> const& dura); + + template <class Duration> + void push(BOOST_THREAD_RV_REF(T) elem, chrono::time_point<clock,Duration> const& tp); + template <class Rep, class Period> + void push(BOOST_THREAD_RV_REF(T) elem, chrono::duration<Rep,Period> const& dura); + + template <class Duration> + queue_op_status try_push(const T& elem, chrono::time_point<clock,Duration> const& tp); + template <class Rep, class Period> + queue_op_status try_push(const T& elem, chrono::duration<Rep,Period> const& dura); + + template <class Duration> + queue_op_status try_push(BOOST_THREAD_RV_REF(T) elem, chrono::time_point<clock,Duration> const& tp); + template <class Rep, class Period> + queue_op_status try_push(BOOST_THREAD_RV_REF(T) elem, chrono::duration<Rep,Period> const& dura); + + private: + T pull(unique_lock<mutex>&); + T pull(lock_guard<mutex>&); + + void pull(unique_lock<mutex>&, T& elem); + void pull(lock_guard<mutex>&, T& elem); + + queue_op_status try_pull(unique_lock<mutex>&, T& elem); + queue_op_status try_pull(lock_guard<mutex>&, T& elem); + + queue_op_status wait_pull(unique_lock<mutex>& lk, T& elem); + + bool wait_until_not_empty_time_reached_or_closed(unique_lock<mutex>&); + T pull_when_time_reached(unique_lock<mutex>&); + template <class Duration> + queue_op_status pull_when_time_reached_until(unique_lock<mutex>&, chrono::time_point<clock,Duration> const& tp, T& elem); + bool time_not_reached(unique_lock<mutex>&); + bool time_not_reached(lock_guard<mutex>&); + bool empty_or_time_not_reached(unique_lock<mutex>&); + bool empty_or_time_not_reached(lock_guard<mutex>&); + + sync_timed_queue(const sync_timed_queue&); + sync_timed_queue& operator=(const sync_timed_queue&); + sync_timed_queue(BOOST_THREAD_RV_REF(sync_timed_queue)); + sync_timed_queue& operator=(BOOST_THREAD_RV_REF(sync_timed_queue)); + }; //end class + + + template <class T, class Clock> + template <class Duration> + void sync_timed_queue<T, Clock>::push(const T& elem, chrono::time_point<clock,Duration> const& tp) + { + super::push(stype(elem,tp)); + } + + template <class T, class Clock> + template <class Rep, class Period> + void sync_timed_queue<T, Clock>::push(const T& elem, chrono::duration<Rep,Period> const& dura) + { + push(elem, clock::now() + dura); + } + + template <class T, class Clock> + template <class Duration> + void sync_timed_queue<T, Clock>::push(BOOST_THREAD_RV_REF(T) elem, chrono::time_point<clock,Duration> const& tp) + { + super::push(stype(boost::move(elem),tp)); + } + + template <class T, class Clock> + template <class Rep, class Period> + void sync_timed_queue<T, Clock>::push(BOOST_THREAD_RV_REF(T) elem, chrono::duration<Rep,Period> const& dura) + { + push(boost::move(elem), clock::now() + dura); + } + + + + template <class T, class Clock> + template <class Duration> + queue_op_status sync_timed_queue<T, Clock>::try_push(const T& elem, chrono::time_point<clock,Duration> const& tp) + { + return super::try_push(stype(elem,tp)); + } + + template <class T, class Clock> + template <class Rep, class Period> + queue_op_status sync_timed_queue<T, Clock>::try_push(const T& elem, chrono::duration<Rep,Period> const& dura) + { + return try_push(elem,clock::now() + dura); + } + + template <class T, class Clock> + template <class Duration> + queue_op_status sync_timed_queue<T, Clock>::try_push(BOOST_THREAD_RV_REF(T) elem, chrono::time_point<clock,Duration> const& tp) + { + return super::try_push(stype(boost::move(elem), tp)); + } + + template <class T, class Clock> + template <class Rep, class Period> + queue_op_status sync_timed_queue<T, Clock>::try_push(BOOST_THREAD_RV_REF(T) elem, chrono::duration<Rep,Period> const& dura) + { + return try_push(boost::move(elem), clock::now() + dura); + } + + /////////////////////////// + template <class T, class Clock> + bool sync_timed_queue<T, Clock>::time_not_reached(unique_lock<mutex>&) + { + return super::data_.top().time_not_reached(); + } + + template <class T, class Clock> + bool sync_timed_queue<T, Clock>::time_not_reached(lock_guard<mutex>&) + { + return super::data_.top().time_not_reached(); + } + + /////////////////////////// + template <class T, class Clock> + bool sync_timed_queue<T, Clock>::wait_until_not_empty_time_reached_or_closed(unique_lock<mutex>& lk) + { + for (;;) + { + if (super::closed(lk)) return true; + while (! super::empty(lk)) { + if (! time_not_reached(lk)) return false; + super::not_empty_.wait_until(lk, super::data_.top().time); + if (super::closed(lk)) return true; + } + if (super::closed(lk)) return true; + super::not_empty_.wait(lk); + } + return false; + } + + /////////////////////////// + template <class T, class Clock> + T sync_timed_queue<T, Clock>::pull_when_time_reached(unique_lock<mutex>& lk) + { + while (time_not_reached(lk)) + { + super::throw_if_closed(lk); + super::not_empty_.wait_until(lk,super::data_.top().time); + super::wait_until_not_empty(lk); + } + return pull(lk); + } + + template <class T, class Clock> + template <class Duration> + queue_op_status + sync_timed_queue<T, Clock>::pull_when_time_reached_until(unique_lock<mutex>& lk, chrono::time_point<clock,Duration> const& tp, T& elem) + { + chrono::time_point<clock,Duration> tpmin = (tp < super::data_.top().time) ? tp : super::data_.top().time; + while (time_not_reached(lk)) + { + super::throw_if_closed(lk); + if (queue_op_status::timeout == super::not_empty_.wait_until(lk, tpmin)) { + if (time_not_reached(lk)) return queue_op_status::not_ready; + return queue_op_status::timeout; + } + } + pull(lk, elem); + return queue_op_status::success; + } + + /////////////////////////// + template <class T, class Clock> + bool sync_timed_queue<T, Clock>::empty_or_time_not_reached(unique_lock<mutex>& lk) + { + if ( super::empty(lk) ) return true; + if ( time_not_reached(lk) ) return true; + return false; + } + template <class T, class Clock> + bool sync_timed_queue<T, Clock>::empty_or_time_not_reached(lock_guard<mutex>& lk) + { + if ( super::empty(lk) ) return true; + if ( time_not_reached(lk) ) return true; + return false; + } + + /////////////////////////// + template <class T, class Clock> + T sync_timed_queue<T, Clock>::pull(unique_lock<mutex>&) + { +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + return boost::move(super::data_.pull().data); +#else + return super::data_.pull().data; +#endif + } + + template <class T, class Clock> + T sync_timed_queue<T, Clock>::pull(lock_guard<mutex>&) + { +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + return boost::move(super::data_.pull().data); +#else + return super::data_.pull().data; +#endif + } + template <class T, class Clock> + T sync_timed_queue<T, Clock>::pull() + { + unique_lock<mutex> lk(super::mtx_); + super::wait_until_not_empty(lk); + return pull_when_time_reached(lk); + } + + /////////////////////////// + template <class T, class Clock> + void sync_timed_queue<T, Clock>::pull(unique_lock<mutex>&, T& elem) + { +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + elem = boost::move(super::data_.pull().data); +#else + elem = super::data_.pull().data; +#endif + } + + template <class T, class Clock> + void sync_timed_queue<T, Clock>::pull(lock_guard<mutex>&, T& elem) + { +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + elem = boost::move(super::data_.pull().data); +#else + elem = super::data_.pull().data; +#endif + } + + template <class T, class Clock> + void sync_timed_queue<T, Clock>::pull(T& elem) + { + unique_lock<mutex> lk(super::mtx_); + super::wait_until_not_empty(lk); + elem = pull_when_time_reached(lk); + } + + ////////////////////// + template <class T, class Clock> + template <class Duration> + queue_op_status + sync_timed_queue<T, Clock>::pull_until(chrono::time_point<clock,Duration> const& tp, T& elem) + { + unique_lock<mutex> lk(super::mtx_); + + if (queue_op_status::timeout == super::wait_until_not_empty_until(lk, tp)) + return queue_op_status::timeout; + return pull_when_time_reached_until(lk, tp, elem); + } + + ////////////////////// + template <class T, class Clock> + template <class Rep, class Period> + queue_op_status + sync_timed_queue<T, Clock>::pull_for(chrono::duration<Rep,Period> const& dura, T& elem) + { + return pull_until(clock::now() + dura, elem); + } + + /////////////////////////// + template <class T, class Clock> + queue_op_status sync_timed_queue<T, Clock>::try_pull(unique_lock<mutex>& lk, T& elem) + { + if ( super::empty(lk) ) + { + if (super::closed(lk)) return queue_op_status::closed; + return queue_op_status::empty; + } + if ( time_not_reached(lk) ) + { + if (super::closed(lk)) return queue_op_status::closed; + return queue_op_status::not_ready; + } + + pull(lk, elem); + return queue_op_status::success; + } + template <class T, class Clock> + queue_op_status sync_timed_queue<T, Clock>::try_pull(lock_guard<mutex>& lk, T& elem) + { + if ( super::empty(lk) ) + { + if (super::closed(lk)) return queue_op_status::closed; + return queue_op_status::empty; + } + if ( time_not_reached(lk) ) + { + if (super::closed(lk)) return queue_op_status::closed; + return queue_op_status::not_ready; + } + pull(lk, elem); + return queue_op_status::success; + } + + template <class T, class Clock> + queue_op_status sync_timed_queue<T, Clock>::try_pull(T& elem) + { + lock_guard<mutex> lk(super::mtx_); + return try_pull(lk, elem); + } + + /////////////////////////// + template <class T, class Clock> + queue_op_status sync_timed_queue<T, Clock>::wait_pull(unique_lock<mutex>& lk, T& elem) + { + if (super::empty(lk)) + { + if (super::closed(lk)) return queue_op_status::closed; + } + bool has_been_closed = wait_until_not_empty_time_reached_or_closed(lk); + if (has_been_closed) return queue_op_status::closed; + pull(lk, elem); + return queue_op_status::success; + } + + template <class T, class Clock> + queue_op_status sync_timed_queue<T, Clock>::wait_pull(T& elem) + { + unique_lock<mutex> lk(super::mtx_); + return wait_pull(lk, elem); + } + +// /////////////////////////// +// template <class T, class Clock> +// queue_op_status sync_timed_queue<T, Clock>::wait_pull(unique_lock<mutex> &lk, T& elem) +// { +// if (super::empty(lk)) +// { +// if (super::closed(lk)) return queue_op_status::closed; +// } +// bool has_been_closed = super::wait_until_not_empty_or_closed(lk); +// if (has_been_closed) return queue_op_status::closed; +// pull(lk, elem); +// return queue_op_status::success; +// } +// template <class T> +// queue_op_status sync_timed_queue<T, Clock>::wait_pull(T& elem) +// { +// unique_lock<mutex> lk(super::mtx_); +// return wait_pull(lk, elem); +// } + + /////////////////////////// + template <class T, class Clock> + queue_op_status sync_timed_queue<T, Clock>::nonblocking_pull(T& elem) + { + unique_lock<mutex> lk(super::mtx_, try_to_lock); + if (! lk.owns_lock()) return queue_op_status::busy; + return try_pull(lk, elem); + } + +} //end concurrent namespace + +using concurrent::sync_timed_queue; + +} //end boost namespace +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/csbl/deque.hpp b/boost/thread/csbl/deque.hpp index 1e48903b1c..2b26a46e1a 100644 --- a/boost/thread/csbl/deque.hpp +++ b/boost/thread/csbl/deque.hpp @@ -19,7 +19,7 @@ // [ // _Ty=non_copyable // ] -#if defined BOOST_THREAD_USES_BOOST_DEQUE || defined BOOST_NO_CXX11_HDR_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES || (defined _MSC_VER && _MSC_FULL_VER < 180020827) +#if defined BOOST_THREAD_USES_BOOST_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES || (defined _MSC_VER && _MSC_FULL_VER < 180020827) #ifndef BOOST_THREAD_USES_BOOST_DEQUE #define BOOST_THREAD_USES_BOOST_DEQUE #endif diff --git a/boost/thread/csbl/devector.hpp b/boost/thread/csbl/devector.hpp new file mode 100644 index 0000000000..c11ad29ba1 --- /dev/null +++ b/boost/thread/csbl/devector.hpp @@ -0,0 +1,100 @@ +// Copyright (C) 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) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_DEVECTOR_HPP +#define BOOST_CSBL_DEVECTOR_HPP + +#include <boost/config.hpp> + +#include <boost/thread/csbl/vector.hpp> +#include <boost/move/detail/move_helpers.hpp> + +namespace boost +{ + namespace csbl + { + template <class T> + class devector + { + typedef vector<T> vector_type; + vector<T> data_; + std::size_t front_index_; + + BOOST_COPYABLE_AND_MOVABLE(devector) + + template <class U> + void priv_push_back(BOOST_FWD_REF(U) x) + { data_.push_back(boost::forward<U>(x)); } + + public: + typedef typename vector_type::size_type size_type; + typedef typename vector_type::reference reference; + typedef typename vector_type::const_reference const_reference; + + + devector() : front_index_(0) {} + devector(devector const& x) BOOST_NOEXCEPT + : data_(x.data_), + front_index_(x.front_index_) + {} + devector(BOOST_RV_REF(devector) x) BOOST_NOEXCEPT + : data_(boost::move(x.data_)), + front_index_(x.front_index_) + {} + + devector& operator=(BOOST_COPY_ASSIGN_REF(devector) x) + { + if (&x != this) + { + data_ = x.data_; + front_index_ = x.front_index_; + } + return *this; + } + + devector& operator=(BOOST_RV_REF(devector) x) + BOOST_NOEXCEPT_IF(vector<T>::allocator_traits_type::propagate_on_container_move_assignment::value) + { + data_ = boost::move(x.data_); + front_index_ = x.front_index_; + return *this; + } + + bool empty() const BOOST_NOEXCEPT + { return data_.size() == front_index_; } + + size_type size() const BOOST_NOEXCEPT + { return data_.size() - front_index_; } + + reference front() BOOST_NOEXCEPT + { return data_[front_index_]; } + + const_reference front() const BOOST_NOEXCEPT + { return data_[front_index_]; } + + reference back() BOOST_NOEXCEPT + { return data_.back(); } + + const_reference back() const BOOST_NOEXCEPT + { return data_.back(); } + + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) + + void pop_front() + { + ++front_index_; + if (empty()) { + data_.clear(); + front_index_=0; + } + } + + }; + } +} +#endif // header diff --git a/boost/thread/csbl/list.hpp b/boost/thread/csbl/list.hpp index c7f10a18d5..52ff45d349 100644 --- a/boost/thread/csbl/list.hpp +++ b/boost/thread/csbl/list.hpp @@ -11,7 +11,7 @@ #include <boost/config.hpp> -#if defined BOOST_THREAD_USES_BOOST_LIST || defined BOOST_NO_CXX11_HDR_LIST || defined BOOST_NO_CXX11_RVALUE_REFERENCES +#if defined BOOST_THREAD_USES_BOOST_LIST || defined BOOST_NO_CXX11_RVALUE_REFERENCES #ifndef BOOST_THREAD_USES_BOOST_LIST #define BOOST_THREAD_USES_BOOST_LIST #endif diff --git a/boost/thread/csbl/queue.hpp b/boost/thread/csbl/queue.hpp new file mode 100644 index 0000000000..1aa645d18f --- /dev/null +++ b/boost/thread/csbl/queue.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2015 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) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_QUEUE_HPP +#define BOOST_CSBL_QUEUE_HPP + +#include <boost/config.hpp> +// MSVC has some trouble instantiating a non_copyable type +//C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(606) : error C2248: 'non_copyable::non_copyable' : cannot access private member declared in class 'non_copyable' +// ..\libs\thread\test\sync\mutual_exclusion\queue_views\single_thread_pass.cpp(24) : see declaration of 'non_copyable::non_copyable' +// ..\libs\thread\test\sync\mutual_exclusion\queue_views\single_thread_pass.cpp(23) : see declaration of 'non_copyable' +// C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(605) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' +// with +// [ +// _Ty=non_copyable +// ] +#if defined BOOST_THREAD_USES_BOOST_QUEUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES || (defined _MSC_VER && _MSC_FULL_VER < 180020827) +#ifndef BOOST_THREAD_USES_BOOST_QUEUE +#define BOOST_THREAD_USES_BOOST_QUEUE +#endif +#include <boost/container/queue.hpp> +#else +#include <queue> +#endif + +namespace boost +{ + namespace csbl + { +#if defined BOOST_THREAD_USES_BOOST_QUEUE + using ::boost::container::queue; + +#else + using ::std::queue; + +#endif + + } +} +#endif // header diff --git a/boost/thread/csbl/vector.hpp b/boost/thread/csbl/vector.hpp index d39c87d114..c77a5b143b 100644 --- a/boost/thread/csbl/vector.hpp +++ b/boost/thread/csbl/vector.hpp @@ -11,7 +11,7 @@ #include <boost/config.hpp> -#if defined BOOST_THREAD_USES_BOOST_VECTOR || defined BOOST_NO_CXX11_HDR_VECTOR || defined BOOST_NO_CXX11_RVALUE_REFERENCES +#if defined BOOST_THREAD_USES_BOOST_VECTOR || defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_MSVC #ifndef BOOST_THREAD_USES_BOOST_VECTOR #define BOOST_THREAD_USES_BOOST_VECTOR #endif diff --git a/boost/thread/detail/invoker.hpp b/boost/thread/detail/invoker.hpp index 44deb1645b..7ab3b33990 100644 --- a/boost/thread/detail/invoker.hpp +++ b/boost/thread/detail/invoker.hpp @@ -134,7 +134,7 @@ namespace boost //BOOST_THREAD_DCL_MOVABLE_BEG(X) invoker<Fp> BOOST_THREAD_DCL_MOVABLE_END #else -#if ! defined BOOST_MSVC +#if ! defined BOOST_MSVC && defined(BOOST_THREAD_PROVIDES_INVOKE) #define BOOST_THREAD_RV_REF_ARG_T(z, n, unused) BOOST_PP_COMMA_IF(n) BOOST_THREAD_RV_REF(Arg##n) #define BOOST_THREAD_RV_REF_A_T(z, n, unused) BOOST_PP_COMMA_IF(n) BOOST_THREAD_RV_REF(A##n) diff --git a/boost/thread/detail/work.hpp b/boost/thread/detail/work.hpp deleted file mode 100644 index 1e10c837bb..0000000000 --- a/boost/thread/detail/work.hpp +++ /dev/null @@ -1,23 +0,0 @@ -// (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) - -#ifndef BOOST_THREAD_DETAIL_WORK_HPP -#define BOOST_THREAD_DETAIL_WORK_HPP - - -#include <boost/thread/detail/nullary_function.hpp> - -namespace boost -{ - namespace thread_detail - { - - typedef detail::nullary_function<void()> work; - } - -} // namespace boost - -#endif // BOOST_THREAD_DETAIL_MEMORY_HPP diff --git a/boost/thread/executors/basic_thread_pool.hpp b/boost/thread/executors/basic_thread_pool.hpp index 11283ddf42..64ba1e90e0 100644 --- a/boost/thread/executors/basic_thread_pool.hpp +++ b/boost/thread/executors/basic_thread_pool.hpp @@ -14,7 +14,7 @@ #include <boost/thread/detail/delete.hpp> #include <boost/thread/detail/move.hpp> #include <boost/thread/scoped_thread.hpp> -#include <boost/thread/sync_queue.hpp> +#include <boost/thread/concurrent_queues/sync_queue.hpp> #include <boost/thread/executors/work.hpp> #include <boost/thread/csbl/vector.hpp> @@ -36,7 +36,7 @@ namespace executors typedef csbl::vector<thread_t> thread_vector; /// the thread safe work queue - sync_queue<work > work_queue; + concurrent::sync_queue<work > work_queue; /// A move aware vector thread_vector threads; @@ -48,22 +48,19 @@ namespace executors */ bool try_executing_one() { - work task; try { - if (work_queue.try_pull_front(task) == queue_op_status::success) + work task; + if (work_queue.try_pull(task) == queue_op_status::success) { task(); return true; } return false; } - catch (std::exception& ) - { - return false; - } catch (...) { + std::terminate(); return false; } } @@ -90,17 +87,14 @@ namespace executors for(;;) { work task; - queue_op_status st = work_queue.wait_pull_front(task); + queue_op_status st = work_queue.wait_pull(task); if (st == queue_op_status::closed) return; task(); } } - catch (std::exception& ) - { - return; - } catch (...) { + std::terminate(); return; } } @@ -134,7 +128,7 @@ namespace executors * * \b Throws: Whatever exception is thrown while initializing the needed resources. */ - basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency()) + basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency()+1) { try { @@ -275,18 +269,18 @@ namespace executors template <typename Closure> void submit(Closure & closure) { - work_queue.push_back(work(closure)); + work_queue.push(work(closure)); } #endif void submit(void (*closure)()) { - work_queue.push_back(work(closure)); + work_queue.push(work(closure)); } template <typename Closure> void submit(BOOST_THREAD_RV_REF(Closure) closure) { - work_queue.push_back(work(boost::forward<Closure>(closure))); + work_queue.push(work(boost::forward<Closure>(closure))); } /** diff --git a/boost/thread/executors/detail/priority_executor_base.hpp b/boost/thread/executors/detail/priority_executor_base.hpp new file mode 100644 index 0000000000..2191c0b37a --- /dev/null +++ b/boost/thread/executors/detail/priority_executor_base.hpp @@ -0,0 +1,77 @@ +// Copyright (C) 2014 Ian Forbed +// Copyright (C) 2014 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) +// + +#ifndef BOOST_THREAD_EXECUTORS_DETAIL_PRIORITY_EXECUTOR_BASE_HPP +#define BOOST_THREAD_EXECUTORS_DETAIL_PRIORITY_EXECUTOR_BASE_HPP + +#include <boost/atomic.hpp> +#include <boost/function.hpp> +#include <boost/thread/thread.hpp> +#include <boost/thread/concurrent_queues/sync_timed_queue.hpp> +#include <boost/thread/executors/work.hpp> + +namespace boost +{ +namespace executors +{ +namespace detail +{ + template <class Queue> + class priority_executor_base + { + public: + //typedef boost::function<void()> work; + typedef executors::work_pq work; + protected: + typedef Queue queue_type; + queue_type _workq; + + priority_executor_base() {} + public: + + ~priority_executor_base() + { + if(!closed()) + { + this->close(); + } + } + + void close() + { + _workq.close(); + } + + bool closed() + { + return _workq.closed(); + } + + void loop() + { + try + { + for(;;) + { + work task; + queue_op_status st = _workq.wait_pull(task); + if (st == queue_op_status::closed) return; + task(); + } + } + catch (...) + { + std::terminate(); + return; + } + } + }; //end class + +} //end detail namespace +} //end executors namespace +} //end boost namespace +#endif diff --git a/boost/thread/executors/detail/scheduled_executor_base.hpp b/boost/thread/executors/detail/scheduled_executor_base.hpp new file mode 100644 index 0000000000..ec0038f7e3 --- /dev/null +++ b/boost/thread/executors/detail/scheduled_executor_base.hpp @@ -0,0 +1,66 @@ +// Copyright (C) 2014 Ian Forbed +// Copyright (C) 2014-2015 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) +// + +#ifndef BOOST_THREAD_EXECUTORS_DETAIL_SCHEDULED_EXECUTOR_BASE_HPP +#define BOOST_THREAD_EXECUTORS_DETAIL_SCHEDULED_EXECUTOR_BASE_HPP + +#include <boost/thread/concurrent_queues/sync_timed_queue.hpp> +#include <boost/thread/executors/detail/priority_executor_base.hpp> +#include <boost/thread/executors/work.hpp> +#include <boost/thread/thread.hpp> + +#include <boost/atomic.hpp> +#include <boost/function.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace executors +{ +namespace detail +{ + template <class Clock=chrono::steady_clock> + class scheduled_executor_base : public priority_executor_base<concurrent::sync_timed_queue<executors::work_pq, Clock > > + { + public: + typedef executors::work_pq work; + typedef Clock clock; + typedef typename clock::duration duration; + typedef typename clock::time_point time_point; + protected: + + scheduled_executor_base() {} + public: + + ~scheduled_executor_base() + { + if(! this->closed()) + { + this->close(); + } + } + + void submit_at(work w, const time_point& tp) + { + this->_workq.push(boost::move(w), tp); + } + + void submit_after(work w, const duration& dura) + { + this->_workq.push(boost::move(w), dura+clock::now()); + } + + }; //end class + +} //end detail namespace +} //end executors namespace +} //end boost namespace + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/executors/inline_executor.hpp b/boost/thread/executors/inline_executor.hpp index bc6bd9fe7e..5dd523184e 100644 --- a/boost/thread/executors/inline_executor.hpp +++ b/boost/thread/executors/inline_executor.hpp @@ -26,6 +26,7 @@ namespace executors /// type-erasure to store the works to do typedef executors::work work; bool closed_; + mutable mutex mtx_; /** * Effects: try to execute one task. * Returns: whether a task has been executed. @@ -66,16 +67,22 @@ namespace executors */ void close() { + lock_guard<mutex> lk(mtx_); closed_ = true; } /** * \b Returns: whether the pool is closed for submissions. */ - bool closed() + bool closed(lock_guard<mutex>& ) { return closed_; } + bool closed() + { + lock_guard<mutex> lk(mtx_); + return closed(lk); + } /** * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible. @@ -93,21 +100,54 @@ namespace executors template <typename Closure> void submit(Closure & closure) { - if (closed()) return; - closure(); + { + lock_guard<mutex> lk(mtx_); + if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + } + try + { + closure(); + } + catch (...) + { + std::terminate(); + return; + } } #endif void submit(void (*closure)()) { - if (closed()) return; - closure(); + { + lock_guard<mutex> lk(mtx_); + if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + } + try + { + closure(); + } + catch (...) + { + std::terminate(); + return; + } } template <typename Closure> void submit(BOOST_THREAD_FWD_REF(Closure) closure) { - if (closed()) return; - closure(); + { + lock_guard<mutex> lk(mtx_); + if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + } + try + { + closure(); + } + catch (...) + { + std::terminate(); + return; + } } /** diff --git a/boost/thread/executors/loop_executor.hpp b/boost/thread/executors/loop_executor.hpp index c2798b4461..e9eadadf9e 100644 --- a/boost/thread/executors/loop_executor.hpp +++ b/boost/thread/executors/loop_executor.hpp @@ -14,7 +14,7 @@ #include <boost/thread/detail/config.hpp> #include <boost/thread/detail/delete.hpp> #include <boost/thread/detail/move.hpp> -#include <boost/thread/sync_queue.hpp> +#include <boost/thread/concurrent_queues/sync_queue.hpp> #include <boost/thread/executors/work.hpp> #include <boost/config/abi_prefix.hpp> @@ -31,7 +31,7 @@ namespace executors typedef executors::work work; private: /// the thread safe work queue - sync_queue<work > work_queue; + concurrent::sync_queue<work > work_queue; public: /** @@ -44,19 +44,16 @@ namespace executors work task; try { - if (work_queue.try_pull_front(task) == queue_op_status::success) + if (work_queue.try_pull(task) == queue_op_status::success) { task(); return true; } return false; } - catch (std::exception& ) - { - return false; - } catch (...) { + std::terminate(); return false; } } @@ -74,19 +71,7 @@ namespace executors } - /** - * The main loop of the worker thread - */ - void worker_thread() - { - while (!closed()) - { - schedule_one_or_yield(); - } - while (try_executing_one()) - { - } - } + public: /// loop_executor is not copyable. @@ -112,9 +97,19 @@ namespace executors } /** - * loop + * The main loop of the worker thread */ - void loop() { worker_thread(); } + void loop() + { + while (!closed()) + { + schedule_one_or_yield(); + } + while (try_executing_one()) + { + } + } + /** * \b Effects: close the \c loop_executor for submissions. * The loop will work until there is no more closures to run. @@ -148,18 +143,18 @@ namespace executors template <typename Closure> void submit(Closure & closure) { - work_queue.push_back(work(closure)); + work_queue.push(work(closure)); } #endif void submit(void (*closure)()) { - work_queue.push_back(work(closure)); + work_queue.push(work(closure)); } template <typename Closure> void submit(BOOST_THREAD_RV_REF(Closure) closure) { - work_queue.push_back(work(boost::forward<Closure>(closure))); + work_queue.push(work(boost::forward<Closure>(closure))); } /** diff --git a/boost/thread/executors/scheduled_thread_pool.hpp b/boost/thread/executors/scheduled_thread_pool.hpp new file mode 100644 index 0000000000..408013b283 --- /dev/null +++ b/boost/thread/executors/scheduled_thread_pool.hpp @@ -0,0 +1,48 @@ +// Copyright (C) 2014 Ian Forbed +// Copyright (C) 2014 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) +// + +#ifndef BOOST_THREAD_EXECUTORS_SCHEDULED_THREAD_POOL_HPP +#define BOOST_THREAD_EXECUTORS_SCHEDULED_THREAD_POOL_HPP + +#include <boost/thread/executors/detail/scheduled_executor_base.hpp> + +namespace boost +{ +namespace executors +{ + + class scheduled_thread_pool : public detail::scheduled_executor_base<> + { + private: + thread_group _workers; + public: + + scheduled_thread_pool(size_t num_threads) : super() + { + for(size_t i = 0; i < num_threads; i++) + { + _workers.create_thread(bind(&super::loop, this)); + } + } + + ~scheduled_thread_pool() + { + this->close(); + _workers.join_all(); + } + + private: + typedef detail::scheduled_executor_base<> super; + }; //end class + +} //end executors namespace + +using executors::scheduled_thread_pool; + +} //end boost +#endif + diff --git a/boost/thread/executors/scheduler.hpp b/boost/thread/executors/scheduler.hpp new file mode 100644 index 0000000000..5796a7d394 --- /dev/null +++ b/boost/thread/executors/scheduler.hpp @@ -0,0 +1,271 @@ +// Copyright (C) 2014 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) +// + +#ifndef BOOST_THREAD_EXECUTORS_SCHEDULER_HPP +#define BOOST_THREAD_EXECUTORS_SCHEDULER_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/executors/detail/scheduled_executor_base.hpp> + +#include <boost/chrono/time_point.hpp> +#include <boost/chrono/duration.hpp> +#include <boost/chrono/system_clocks.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace executors + { + /// Wraps the reference to an executor and a function to make a work that submit the function using the executor. + template <class Executor, class Function> + class resubmitter + { + public: + resubmitter(Executor& ex, Function funct) : + ex(ex), + funct(boost::move(funct)) + {} + + void operator()() + { + ex.submit(funct); + } + + private: + Executor& ex; + Function funct; + }; + + /// resubmitter factory + template <class Executor, class Function> + resubmitter<Executor, typename decay<Function>::type> + resubmit(Executor& ex, BOOST_THREAD_FWD_REF(Function) funct) { + return resubmitter<Executor, typename decay<Function>::type >(ex, boost::move(funct)); + } + + /// Wraps references to a @c Scheduler and an @c Executor providing an @c Executor that + /// resubmit the function using the referenced Executor at a given @c time_point known at construction. + template <class Scheduler, class Executor> + class resubmit_at_executor + { + public: + typedef typename Scheduler::clock clock; + typedef typename Scheduler::work work; + + template <class Duration> + resubmit_at_executor(Scheduler& sch, Executor& ex, chrono::time_point<clock, Duration> const& tp) : + sch(sch), + ex(ex), + tp(tp), + is_closed(false) + { + } + + ~resubmit_at_executor() + { + close(); + } + + template <class Work> + void submit(BOOST_THREAD_FWD_REF(Work) w) + { + if (closed()) + { + BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + } + sch.submit_at(resubmit(ex,boost::forward<Work>(w)), tp); + } + + Executor& underlying_executor() + { + return ex; + } + Scheduler& underlying_scheduler() + { + return sch; + } + + void close() + { + is_closed = true; + } + + bool closed() + { + return is_closed || sch.closed() || ex.closed(); + } + + private: + Scheduler& sch; + Executor& ex; + typename clock::time_point tp; + bool is_closed; + }; + + + /// Expression template helper storing a pair of references to an @c Scheduler and an @c Executor + /// It provides factory helper functions such as at/after that convert these a pair of @c Scheduler @c Executor + /// into an new @c Executor that submit the work using the referenced @c Executor at/after a specific time/duration + /// respectively, using the referenced @Scheduler. + template <class Scheduler, class Executor> + class scheduler_executor_wrapper + { + public: + typedef typename Scheduler::clock clock; + typedef typename Scheduler::work work; + typedef resubmit_at_executor<Scheduler, Executor> the_executor; + + scheduler_executor_wrapper(Scheduler& sch, Executor& ex) : + sch(sch), + ex(ex) + {} + + ~scheduler_executor_wrapper() + { + } + + Executor& underlying_executor() + { + return ex; + } + Scheduler& underlying_scheduler() + { + return sch; + } + + template <class Rep, class Period> + the_executor after(chrono::duration<Rep,Period> const& rel_time) + { + return at(clock::now() + rel_time ); + } + + template <class Duration> + the_executor at(chrono::time_point<clock,Duration> const& abs_time) + { + return the_executor(sch, ex, abs_time); + } + + private: + Scheduler& sch; + Executor& ex; + }; //end class + + /// Wraps a reference to a @c Scheduler providing an @c Executor that + /// run the function at a given @c time_point known at construction. + template <class Scheduler> + class at_executor + { + public: + typedef typename Scheduler::clock clock; + typedef typename Scheduler::work work; + typedef typename clock::time_point time_point; + + template <class Duration> + at_executor(Scheduler& sch, chrono::time_point<clock,Duration> const& tp) : + sch(sch), + tp(tp), + is_closed(false) + {} + + ~at_executor() + { + close(); + } + + Scheduler& underlying_scheduler() + { + return sch; + } + + void close() + { + is_closed = true; + } + + bool closed() + { + return is_closed || sch.closed(); + } + + template <class Work> + void submit(BOOST_THREAD_FWD_REF(Work) w) + { + if (closed()) + { + BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + } + sch.submit_at(boost::forward<Work>(w), tp); + } + + template <class Executor> + resubmit_at_executor<Scheduler, Executor> on(Executor& ex) + { + return resubmit_at_executor<Scheduler, Executor>(sch, ex, tp); + } + + private: + Scheduler& sch; + time_point tp; + bool is_closed; + }; //end class + + /// A @c Scheduler using a specific thread. Note that a Scheduler is not an Executor. + /// It provides factory helper functions such as at/after that convert a @c Scheduler into an @c Executor + /// that submit the work at/after a specific time/duration respectively. + template <class Clock = chrono::steady_clock> + class scheduler : public detail::scheduled_executor_base<Clock> + { + public: + typedef typename detail::scheduled_executor_base<Clock>::work work; + + typedef Clock clock; + + scheduler() + : super(), + thr(&super::loop, this) {} + + ~scheduler() + { + this->close(); + thr.join(); + } + template <class Ex> + scheduler_executor_wrapper<scheduler, Ex> on(Ex& ex) + { + return scheduler_executor_wrapper<scheduler, Ex>(*this, ex); + } + + template <class Rep, class Period> + at_executor<scheduler> after(chrono::duration<Rep,Period> const& rel_time) + { + return at(rel_time + clock::now()); + } + + template <class Duration> + at_executor<scheduler> at(chrono::time_point<clock,Duration> const& tp) + { + return at_executor<scheduler>(*this, tp); + } + + private: + typedef detail::scheduled_executor_base<Clock> super; + thread thr; + }; + + + } + using executors::resubmitter; + using executors::resubmit; + using executors::resubmit_at_executor; + using executors::scheduler_executor_wrapper; + using executors::at_executor; + using executors::scheduler; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/executors/scheduling_adaptor.hpp b/boost/thread/executors/scheduling_adaptor.hpp new file mode 100644 index 0000000000..ac0a0acbce --- /dev/null +++ b/boost/thread/executors/scheduling_adaptor.hpp @@ -0,0 +1,51 @@ +// Copyright (C) 2014 Ian Forbed +// Copyright (C) 2014 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) +// + +#ifndef BOOST_THREAD_EXECUTORS_SCHEDULING_ADAPTOR_HPP +#define BOOST_THREAD_EXECUTORS_SCHEDULING_ADAPTOR_HPP + +#include <boost/thread/executors/detail/scheduled_executor_base.hpp> + +namespace boost +{ +namespace executors +{ + + template <typename Executor> + class scheduling_adpator : public detail::scheduled_executor_base<> + { + private: + Executor& _exec; + thread _scheduler; + public: + + scheduling_adpator(Executor& ex) + : super(), + _exec(ex), + _scheduler(&super::loop, this) {} + + ~scheduling_adpator() + { + this->close(); + _scheduler.join(); + } + + Executor& underlying_executor() + { + return _exec; + } + + private: + typedef detail::scheduled_executor_base<> super; + }; //end class + +} //end executors + + using executors::scheduling_adpator; + +} //end boost +#endif diff --git a/boost/thread/executors/serial_executor.hpp b/boost/thread/executors/serial_executor.hpp index dae1014b47..6f4266668f 100644 --- a/boost/thread/executors/serial_executor.hpp +++ b/boost/thread/executors/serial_executor.hpp @@ -12,7 +12,7 @@ #include <boost/thread/detail/config.hpp> #include <boost/thread/detail/delete.hpp> #include <boost/thread/detail/move.hpp> -#include <boost/thread/sync_queue.hpp> +#include <boost/thread/concurrent_queues/sync_queue.hpp> #include <boost/thread/executors/work.hpp> #include <boost/thread/executors/generic_executor_ref.hpp> #include <boost/thread/future.hpp> @@ -33,7 +33,7 @@ namespace executors typedef scoped_thread<> thread_t; /// the thread safe work queue - sync_queue<work > work_queue; + concurrent::sync_queue<work > work_queue; generic_executor_ref ex; thread_t thr; @@ -43,8 +43,13 @@ namespace executors try_executing_one_task(work& task, boost::promise<void> &p) : task(task), p(p) {} void operator()() { - task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here. - p.set_value(); + try { + task(); + p.set_value(); + } catch (...) + { + p.set_exception(current_exception()); + } } }; public: @@ -52,7 +57,7 @@ namespace executors * \par Returns * The underlying executor wrapped on a generic executor reference. */ - generic_executor_ref underlying_executor() BOOST_NOEXCEPT { return ex; } + generic_executor_ref& underlying_executor() BOOST_NOEXCEPT { return ex; } /** * Effects: try to execute one task. @@ -64,27 +69,19 @@ namespace executors work task; try { - if (work_queue.try_pull_front(task) == queue_op_status::success) + if (work_queue.try_pull(task) == queue_op_status::success) { boost::promise<void> p; try_executing_one_task tmp(task,p); ex.submit(tmp); -// ex.submit([&task, &p]() -// { -// task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here. -// p.set_value(); -// }); p.get_future().wait(); return true; } return false; } - catch (std::exception& ) - { - return false; - } catch (...) { + std::terminate(); return false; } } @@ -136,7 +133,7 @@ namespace executors */ ~serial_executor() { - // signal to all the worker thread that there will be no more submissions. + // signal to the worker thread that there will be no more submissions. close(); } @@ -173,18 +170,18 @@ namespace executors template <typename Closure> void submit(Closure & closure) { - work_queue.push_back(work(closure)); + work_queue.push(work(closure)); } #endif void submit(void (*closure)()) { - work_queue.push_back(work(closure)); + work_queue.push(work(closure)); } template <typename Closure> void submit(BOOST_THREAD_RV_REF(Closure) closure) { - work_queue.push_back(work(boost::forward<Closure>(closure))); + work_queue.push(work(boost::forward<Closure>(closure))); } /** diff --git a/boost/thread/executors/serial_executor_cont.hpp b/boost/thread/executors/serial_executor_cont.hpp new file mode 100644 index 0000000000..1c4cc14aad --- /dev/null +++ b/boost/thread/executors/serial_executor_cont.hpp @@ -0,0 +1,170 @@ +// Copyright (C) 2015 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) +// +// 2013/11 Vicente J. Botet Escriba +// first implementation of a simple serial scheduler. + +#ifndef BOOST_THREAD_SERIAL_EXECUTOR_CONT_HPP +#define BOOST_THREAD_SERIAL_EXECUTOR_CONT_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/concurrent_queues/sync_queue.hpp> +#include <boost/thread/executors/work.hpp> +#include <boost/thread/executors/generic_executor_ref.hpp> +#include <boost/thread/future.hpp> +#include <boost/thread/scoped_thread.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace executors +{ + class serial_executor_cont + { + public: + /// type-erasure to store the works to do + typedef executors::work work; + private: + + generic_executor_ref ex_; + future<void> fut_; // protected by mtx_ + bool closed_; // protected by mtx_ + mutex mtx_; + + struct continuation { + work task; + template <class X> + struct result { + typedef void type; + }; + continuation(BOOST_THREAD_RV_REF(work) tsk) + : task(boost::move(tsk)) {} + void operator()(future<void> f) + { + try { + task(); + } catch (...) { + std::terminate(); + } + } + }; + + bool closed(lock_guard<mutex>&) const + { + return closed_; + } + public: + /** + * \par Returns + * The underlying executor wrapped on a generic executor reference. + */ + generic_executor_ref& underlying_executor() BOOST_NOEXCEPT { return ex_; } + + /// serial_executor_cont is not copyable. + BOOST_THREAD_NO_COPYABLE(serial_executor_cont) + + /** + * \b Effects: creates a serial executor that runs closures in fifo order using one the associated executor. + * + * \b Throws: Whatever exception is thrown while initializing the needed resources. + * + * \b Notes: + * * The lifetime of the associated executor must outlive the serial executor. + * * The current implementation doesn't support submission from synchronous continuation, that is, + * - the executor must execute the continuation asynchronously or + * - the continuation can not submit to this serial executor. + */ + template <class Executor> + serial_executor_cont(Executor& ex) + : ex_(ex), fut_(make_ready_future()), closed_(false) + { + } + /** + * \b Effects: Destroys the thread pool. + * + * \b Synchronization: The completion of all the closures happen before the completion of the \c serial_executor_cont destructor. + */ + ~serial_executor_cont() + { + // signal to the worker thread that there will be no more submissions. + close(); + } + + /** + * \b Effects: close the \c serial_executor_cont for submissions. + * The loop will work until there is no more closures to run. + */ + void close() + { + lock_guard<mutex> lk(mtx_); + closed_ = true;; + } + + /** + * \b Returns: whether the pool is closed for submissions. + */ + bool closed() + { + lock_guard<mutex> lk(mtx_); + return closed(lk); + } + + /** + * Effects: none. + * Returns: always false. + * Throws: No. + * Remark: A serial executor can not execute one of its pending tasks as the tasks depends on the other tasks. + */ + bool try_executing_one() + { + return false; + } + + /** + * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible. + * + * \b Effects: The specified \c closure will be scheduled for execution after the last submitted closure finish. + * If the invoked closure throws an exception the \c serial_executor_cont will call \c std::terminate, as is the case with threads. + * + * \b Throws: \c sync_queue_is_closed if the executor is closed. + * Whatever exception that can be throw while storing the closure. + * + */ + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename Closure> + void submit(Closure & closure) + { + lock_guard<mutex> lk(mtx_); + if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + fut_ = fut_.then(ex_, continuation(work(closure))); + } +#endif + void submit(void (*closure)()) + { + lock_guard<mutex> lk(mtx_); + if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + fut_ = fut_.then(ex_, continuation(work(closure))); + } + + template <typename Closure> + void submit(BOOST_THREAD_RV_REF(Closure) closure) + { + lock_guard<mutex> lk(mtx_); + if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + fut_ = fut_.then(ex_, continuation(work(boost::forward<Closure>(closure)))); + } + + }; +} +using executors::serial_executor_cont; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/executors/thread_executor.hpp b/boost/thread/executors/thread_executor.hpp index 9fc3362fde..a8cd5c212f 100644 --- a/boost/thread/executors/thread_executor.hpp +++ b/boost/thread/executors/thread_executor.hpp @@ -15,6 +15,8 @@ #include <boost/thread/executors/work.hpp> #include <boost/thread/executors/executor.hpp> #include <boost/thread/thread_only.hpp> +#include <boost/thread/scoped_thread.hpp> +#include <boost/thread/csbl/vector.hpp> #include <boost/config/abi_prefix.hpp> @@ -28,6 +30,11 @@ namespace executors /// type-erasure to store the works to do typedef executors::work work; bool closed_; + typedef scoped_thread<> thread_t; + typedef csbl::vector<thread_t> threads_type; + threads_type threads_; + mutable mutex mtx_; + /** * Effects: try to execute one task. * Returns: whether a task has been executed. @@ -52,7 +59,7 @@ namespace executors { } /** - * \b Effects: Destroys the inline executor. + * \b Effects: Waits for closures (if any) to complete, then joins and destroys the threads. * * \b Synchronization: The completion of all the closures happen before the completion of the \c thread_executor destructor. */ @@ -60,6 +67,7 @@ namespace executors { // signal to all the worker thread that there will be no more submissions. close(); + // all the scoped threads will join before destroying } /** @@ -68,16 +76,22 @@ namespace executors */ void close() { + lock_guard<mutex> lk(mtx_); closed_ = true; } /** * \b Returns: whether the pool is closed for submissions. */ - bool closed() + bool closed(lock_guard<mutex>& ) { return closed_; } + bool closed() + { + lock_guard<mutex> lk(mtx_); + return closed(lk); + } /** * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible. @@ -95,24 +109,30 @@ namespace executors template <typename Closure> void submit(Closure & closure) { - if (closed()) return; + lock_guard<mutex> lk(mtx_); + if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + threads_.reserve(threads_.size() + 1); thread th(closure); - th.detach(); + threads_.push_back(thread_t(boost::move(th))); } #endif void submit(void (*closure)()) { - if (closed()) return; + lock_guard<mutex> lk(mtx_); + if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + threads_.reserve(threads_.size() + 1); thread th(closure); - th.detach(); + threads_.push_back(thread_t(boost::move(th))); } template <typename Closure> void submit(BOOST_THREAD_FWD_REF(Closure) closure) { - if (closed()) return; + lock_guard<mutex> lk(mtx_); + if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + threads_.reserve(threads_.size() + 1); thread th(boost::forward<Closure>(closure)); - th.detach(); + threads_.push_back(thread_t(boost::move(th))); } /** diff --git a/boost/thread/executors/work.hpp b/boost/thread/executors/work.hpp index df1512cd95..bdaf7651b9 100644 --- a/boost/thread/executors/work.hpp +++ b/boost/thread/executors/work.hpp @@ -8,36 +8,23 @@ #define BOOST_THREAD_EXECUTORS_WORK_HPP #include <boost/thread/detail/config.hpp> - -#if ! defined BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE \ - && ! defined BOOST_THREAD_EXECUTORS_WORK_DONT_ACCEPT_MOVABLE -#define BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE -//#define BOOST_THREAD_EXECUTORS_WORK_DONT_ACCEPT_MOVABLE -#endif - -#if defined BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE - #include <boost/thread/detail/nullary_function.hpp> +#include <boost/thread/csbl/functional.hpp> namespace boost { namespace executors { typedef detail::nullary_function<void()> work; - } -} // namespace boost +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef detail::nullary_function<void()> work_pq; + //typedef csbl::function<void()> work_pq; #else -#include <boost/thread/csbl/functional.hpp> - -namespace boost -{ - namespace executors - { - typedef csbl::function<void()> work; + typedef csbl::function<void()> work_pq; +#endif } } // namespace boost -#endif #endif // BOOST_THREAD_EXECUTORS_WORK_HPP diff --git a/boost/thread/experimental/config/inline_namespace.hpp b/boost/thread/experimental/config/inline_namespace.hpp new file mode 100644 index 0000000000..9c3b081fbe --- /dev/null +++ b/boost/thread/experimental/config/inline_namespace.hpp @@ -0,0 +1,23 @@ +#ifndef BOOST_THREAD_EXPERIMENTAL_CONFIG_INLINE_NAMESPACE_HPP +#define BOOST_THREAD_EXPERIMENTAL_CONFIG_INLINE_NAMESPACE_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/config.hpp> + +#if !defined(BOOST_NO_CXX11_INLINE_NAMESPACES) +# define BOOST_THREAD_INLINE_NAMESPACE(name) inline namespace name +#else +# define BOOST_THREAD_INLINE_NAMESPACE(name) namespace name +#endif + + +#endif diff --git a/boost/thread/experimental/exception_list.hpp b/boost/thread/experimental/exception_list.hpp new file mode 100644 index 0000000000..748bfa85ee --- /dev/null +++ b/boost/thread/experimental/exception_list.hpp @@ -0,0 +1,16 @@ +#ifndef BOOST_THREAD_EXPERIMENTAL_EXCEPTION_LIST_HPP +#define BOOST_THREAD_EXPERIMENTAL_EXCEPTION_LIST_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/experimental/parallel/v1/exception_list.hpp> + +#endif diff --git a/boost/thread/experimental/parallel/v1/exception_list.hpp b/boost/thread/experimental/parallel/v1/exception_list.hpp new file mode 100644 index 0000000000..e4d3354f1c --- /dev/null +++ b/boost/thread/experimental/parallel/v1/exception_list.hpp @@ -0,0 +1,70 @@ +#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_EXCEPTION_LIST_HPP +#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_EXCEPTION_LIST_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/experimental/parallel/v1/inline_namespace.hpp> + +#include <boost/exception_ptr.hpp> +#include <exception> +#include <list> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace experimental +{ +namespace parallel +{ +BOOST_THREAD_INLINE_NAMESPACE(v1) +{ + + class BOOST_SYMBOL_VISIBLE exception_list: public std::exception + { + typedef std::list<exception_ptr> exception_ptr_list; + exception_ptr_list list_; + public: + typedef exception_ptr_list::const_iterator const_iterator; + + ~exception_list() BOOST_NOEXCEPT_OR_NOTHROW {} + + void add(exception_ptr const& e) + { + list_.push_back(e); + } + size_t size() const BOOST_NOEXCEPT + { + return list_.size(); + } + const_iterator begin() const BOOST_NOEXCEPT + { + return list_.begin(); + } + const_iterator end() const BOOST_NOEXCEPT + { + return list_.end(); + } + const char* what() const BOOST_NOEXCEPT_OR_NOTHROW + { + return "exception_list"; + } + + }; +} + +} // parallel +} // experimental +} // boost +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/experimental/parallel/v1/inline_namespace.hpp b/boost/thread/experimental/parallel/v1/inline_namespace.hpp new file mode 100644 index 0000000000..a607e53c46 --- /dev/null +++ b/boost/thread/experimental/parallel/v1/inline_namespace.hpp @@ -0,0 +1,28 @@ +#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_INLINE_NAMESPACE_HPP +#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_INLINE_NAMESPACE_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/experimental/config/inline_namespace.hpp> +namespace boost { +namespace experimental { +namespace parallel { + + BOOST_THREAD_INLINE_NAMESPACE(v1) {} + +#if defined(BOOST_NO_CXX11_INLINE_NAMESPACES) + using namespace v1; +#endif + +} +} +} +#endif diff --git a/boost/thread/experimental/parallel/v2/inline_namespace.hpp b/boost/thread/experimental/parallel/v2/inline_namespace.hpp new file mode 100644 index 0000000000..52d8e2904e --- /dev/null +++ b/boost/thread/experimental/parallel/v2/inline_namespace.hpp @@ -0,0 +1,29 @@ +#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_INLINE_NAMESPACE_HPP +#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_INLINE_NAMESPACE_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/experimental/config/inline_namespace.hpp> + +namespace boost { +namespace experimental { +namespace parallel { + + BOOST_THREAD_INLINE_NAMESPACE(v2) {} + +#if defined(BOOST_NO_CXX11_INLINE_NAMESPACES) + using namespace v2; +#endif + +} +} +} +#endif diff --git a/boost/thread/experimental/parallel/v2/task_region.hpp b/boost/thread/experimental/parallel/v2/task_region.hpp new file mode 100755 index 0000000000..3a278c500f --- /dev/null +++ b/boost/thread/experimental/parallel/v2/task_region.hpp @@ -0,0 +1,316 @@ +#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_TASK_REGION_HPP +#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_TASK_REGION_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014-2015. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include <boost/thread/detail/config.hpp> + +#include <boost/thread/future.hpp> +#if defined BOOST_THREAD_PROVIDES_EXECUTORS +#include <boost/thread/executors/basic_thread_pool.hpp> +#endif +#include <boost/thread/experimental/exception_list.hpp> +#include <boost/thread/experimental/parallel/v2/inline_namespace.hpp> +#include <boost/thread/detail/move.hpp> + +#include <boost/config/abi_prefix.hpp> + +#define BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED + +namespace boost +{ +namespace experimental +{ +namespace parallel +{ +BOOST_THREAD_INLINE_NAMESPACE(v2) +{ + class BOOST_SYMBOL_VISIBLE task_canceled_exception: public std::exception + { + public: + //task_canceled_exception() BOOST_NOEXCEPT {} + //task_canceled_exception(const task_canceled_exception&) BOOST_NOEXCEPT {} + //task_canceled_exception& operator=(const task_canceled_exception&) BOOST_NOEXCEPT {} + virtual const char* what() const BOOST_NOEXCEPT_OR_NOTHROW + { return "task_canceled_exception";} + }; + + template <class Executor> + class task_region_handle_gen; + + namespace detail + { + void handle_task_region_exceptions(exception_list& errors) + { + try { + throw; + } +#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED + catch (task_canceled_exception& ex) + { + } +#endif + catch (exception_list const& el) + { + for (exception_list::const_iterator it = el.begin(); it != el.end(); ++it) + { + boost::exception_ptr const& e = *it; + try { + rethrow_exception(e); + } + catch (...) + { + handle_task_region_exceptions(errors); + } + } + } + catch (...) + { + errors.add(boost::current_exception()); + } + } + +#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED + template <class TRH, class F> + struct wrapped + { + TRH& tr; + F f; + wrapped(TRH& tr, BOOST_THREAD_RV_REF(F) f) : tr(tr), f(move(f)) + {} + void operator()() + { + try + { + f(); + } + catch (...) + { + lock_guard<mutex> lk(tr.mtx); + tr.canceled = true; + throw; + } + } + }; +#endif + } + + template <class Executor> + class task_region_handle_gen + { + private: + // Private members and friends +#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED + template <class TRH, class F> + friend struct detail::wrapped; +#endif + template <typename F> + friend void task_region(BOOST_THREAD_FWD_REF(F) f); + template<typename F> + friend void task_region_final(BOOST_THREAD_FWD_REF(F) f); + template <class Ex, typename F> + friend void task_region(Ex&, BOOST_THREAD_FWD_REF(F) f); + template<class Ex, typename F> + friend void task_region_final(Ex&, BOOST_THREAD_FWD_REF(F) f); + + void wait_all() + { + wait_for_all(group.begin(), group.end()); + + for (group_type::iterator it = group.begin(); it != group.end(); ++it) + { + future<void>& f = *it; + if (f.has_exception()) + { + try + { + boost::rethrow_exception(f.get_exception_ptr()); + } + catch (...) + { + detail::handle_task_region_exceptions(exs); + } + } + } + if (exs.size() != 0) + { + boost::throw_exception(exs); + } + } +protected: +#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && ! defined BOOST_THREAD_PROVIDES_EXECUTORS + task_region_handle_gen() + {} +#endif + +#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS + task_region_handle_gen() + : canceled(false) + , ex(0) + {} + task_region_handle_gen(Executor& ex) + : canceled(false) + , ex(&ex) + {} + +#endif + +#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS + task_region_handle_gen() + : ex(0) + {} + task_region_handle_gen(Executor& ex) + : ex(&ex) + {} +#endif + +#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && ! defined BOOST_THREAD_PROVIDES_EXECUTORS + task_region_handle_gen() + : canceled(false) + { + } +#endif + + ~task_region_handle_gen() + { + //wait_all(); + } + +#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED + mutable mutex mtx; + bool canceled; +#endif +#if defined BOOST_THREAD_PROVIDES_EXECUTORS + Executor* ex; +#endif + exception_list exs; + typedef csbl::vector<future<void> > group_type; + group_type group; + + public: + BOOST_DELETED_FUNCTION(task_region_handle_gen(const task_region_handle_gen&)) + BOOST_DELETED_FUNCTION(task_region_handle_gen& operator=(const task_region_handle_gen&)) + BOOST_DELETED_FUNCTION(task_region_handle_gen* operator&() const) + + public: + template<typename F> + void run(BOOST_THREAD_FWD_REF(F) f) + { +#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED + { + lock_guard<mutex> lk(mtx); + if (canceled) { + boost::throw_exception(task_canceled_exception()); + } + } +#if defined BOOST_THREAD_PROVIDES_EXECUTORS + group.push_back(async(*ex, detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f)))); +#else + group.push_back(async(detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f)))); +#endif +#else +#if defined BOOST_THREAD_PROVIDES_EXECUTORS + group.push_back(async(*ex, forward<F>(f))); +#else + group.push_back(async(forward<F>(f))); +#endif +#endif + } + + void wait() + { +#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED + { + lock_guard<mutex> lk(mtx); + if (canceled) { + boost::throw_exception(task_canceled_exception()); + } + } +#endif + wait_all(); + } + }; +#if defined BOOST_THREAD_PROVIDES_EXECUTORS + typedef basic_thread_pool default_executor; +#else + typedef int default_executor; +#endif + class task_region_handle : + public task_region_handle_gen<default_executor> + { + default_executor tp; + template <typename F> + friend void task_region(BOOST_THREAD_FWD_REF(F) f); + template<typename F> + friend void task_region_final(BOOST_THREAD_FWD_REF(F) f); + + protected: + task_region_handle() : task_region_handle_gen<default_executor>() + { +#if defined BOOST_THREAD_PROVIDES_EXECUTORS + ex = &tp; +#endif + } + BOOST_DELETED_FUNCTION(task_region_handle(const task_region_handle&)) + BOOST_DELETED_FUNCTION(task_region_handle& operator=(const task_region_handle&)) + BOOST_DELETED_FUNCTION(task_region_handle* operator&() const) + + }; + + template <typename Executor, typename F> + void task_region_final(Executor& ex, BOOST_THREAD_FWD_REF(F) f) + { + task_region_handle_gen<Executor> tr(ex); + try + { + f(tr); + } + catch (...) + { + detail::handle_task_region_exceptions(tr.exs); + } + tr.wait_all(); + } + + template <typename Executor, typename F> + void task_region(Executor& ex, BOOST_THREAD_FWD_REF(F) f) + { + task_region_final(ex, forward<F>(f)); + } + + template <typename F> + void task_region_final(BOOST_THREAD_FWD_REF(F) f) + { + task_region_handle tr; + try + { + f(tr); + } + catch (...) + { + detail::handle_task_region_exceptions(tr.exs); + } + tr.wait_all(); + } + + template <typename F> + void task_region(BOOST_THREAD_FWD_REF(F) f) + { + task_region_final(forward<F>(f)); + } + +} // v2 +} // parallel +} // experimental +} // boost + +#include <boost/config/abi_suffix.hpp> + +#endif // header diff --git a/boost/thread/experimental/task_region.hpp b/boost/thread/experimental/task_region.hpp new file mode 100644 index 0000000000..9b60d8b19e --- /dev/null +++ b/boost/thread/experimental/task_region.hpp @@ -0,0 +1,16 @@ +#ifndef BOOST_THREAD_EXPERIMENTAL_TASK_REGION_HPP +#define BOOST_THREAD_EXPERIMENTAL_TASK_REGION_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. 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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/experimental/parallel/v2/task_region.hpp> + +#endif diff --git a/boost/thread/future.hpp b/boost/thread/future.hpp index a1e69c355a..e6e22363aa 100644 --- a/boost/thread/future.hpp +++ b/boost/thread/future.hpp @@ -1,5 +1,5 @@ // (C) Copyright 2008-10 Anthony Williams -// (C) Copyright 2011-2014 Vicente J. Botet Escriba +// (C) Copyright 2011-2015 Vicente J. Botet Escriba // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -15,49 +15,52 @@ #ifndef BOOST_NO_EXCEPTIONS -#include <boost/core/scoped_enum.hpp> -#include <stdexcept> -#include <iostream> -#include <boost/thread/exceptional_ptr.hpp> +#include <boost/thread/condition_variable.hpp> #include <boost/thread/detail/move.hpp> #include <boost/thread/detail/invoker.hpp> #include <boost/thread/detail/invoke.hpp> -#include <boost/thread/thread_time.hpp> -#include <boost/thread/mutex.hpp> -#include <boost/thread/condition_variable.hpp> +#include <boost/thread/detail/is_convertible.hpp> +#include <boost/thread/exceptional_ptr.hpp> +#include <boost/thread/futures/future_error.hpp> +#include <boost/thread/futures/future_error_code.hpp> +#include <boost/thread/futures/future_status.hpp> +#include <boost/thread/futures/is_future_type.hpp> +#include <boost/thread/futures/launch.hpp> +#include <boost/thread/futures/wait_for_all.hpp> +#include <boost/thread/futures/wait_for_any.hpp> #include <boost/thread/lock_algorithms.hpp> #include <boost/thread/lock_types.hpp> -#include <boost/exception_ptr.hpp> -#include <boost/shared_ptr.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/thread_only.hpp> +#include <boost/thread/thread_time.hpp> + #if defined BOOST_THREAD_FUTURE_USES_OPTIONAL #include <boost/optional.hpp> #else #include <boost/thread/csbl/memory/unique_ptr.hpp> -//#include <boost/move/make_unique.hpp> #endif -#include <boost/type_traits/is_fundamental.hpp> -#include <boost/thread/detail/is_convertible.hpp> -#include <boost/type_traits/decay.hpp> -#include <boost/type_traits/is_void.hpp> -#include <boost/type_traits/conditional.hpp> -#include <boost/config.hpp> -#include <boost/throw_exception.hpp> -#include <algorithm> -#include <boost/function.hpp> + +#include <boost/assert.hpp> #include <boost/bind.hpp> +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/system_clocks.hpp> +#endif +#include <boost/core/enable_if.hpp> #include <boost/core/ref.hpp> -#include <boost/scoped_array.hpp> #include <boost/enable_shared_from_this.hpp> -#include <boost/core/enable_if.hpp> - -#include <list> +#include <boost/exception_ptr.hpp> +#include <boost/function.hpp> #include <boost/next_prior.hpp> -#include <vector> +#include <boost/scoped_array.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/throw_exception.hpp> +#include <boost/type_traits/conditional.hpp> +#include <boost/type_traits/decay.hpp> +#include <boost/type_traits/is_copy_constructible.hpp> +#include <boost/type_traits/is_fundamental.hpp> +#include <boost/type_traits/is_void.hpp> +#include <boost/utility/result_of.hpp> -#include <boost/thread/future_error_code.hpp> -#ifdef BOOST_THREAD_USES_CHRONO -#include <boost/chrono/system_clocks.hpp> -#endif #if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS #include <boost/thread/detail/memory.hpp> @@ -67,14 +70,16 @@ #endif #endif -#include <boost/utility/result_of.hpp> -#include <boost/thread/thread_only.hpp> - #if defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY #include <boost/thread/csbl/tuple.hpp> #include <boost/thread/csbl/vector.hpp> #endif +#include <algorithm> +#include <list> +#include <vector> +#include <utility> + #if defined BOOST_THREAD_PROVIDES_FUTURE #define BOOST_THREAD_FUTURE future #else @@ -83,134 +88,26 @@ namespace boost { - - //enum class launch - BOOST_SCOPED_ENUM_DECLARE_BEGIN(launch) - { - none = 0, - async = 1, - deferred = 2, -#ifdef BOOST_THREAD_PROVIDES_EXECUTORS - executor = 4, -#endif - any = async | deferred - } - BOOST_SCOPED_ENUM_DECLARE_END(launch) - - //enum class future_status - BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_status) - { - ready, - timeout, - deferred - } - BOOST_SCOPED_ENUM_DECLARE_END(future_status) - - class BOOST_SYMBOL_VISIBLE future_error - : public std::logic_error - { - system::error_code ec_; - public: - future_error(system::error_code ec) - : logic_error(ec.message()), - ec_(ec) - { - } - - const system::error_code& code() const BOOST_NOEXCEPT - { - return ec_; - } - }; - - class BOOST_SYMBOL_VISIBLE future_uninitialized: - public future_error - { - public: - future_uninitialized() : - future_error(system::make_error_code(future_errc::no_state)) - {} - }; - class BOOST_SYMBOL_VISIBLE broken_promise: - public future_error - { - public: - broken_promise(): - future_error(system::make_error_code(future_errc::broken_promise)) - {} - }; - class BOOST_SYMBOL_VISIBLE future_already_retrieved: - public future_error - { - public: - future_already_retrieved(): - future_error(system::make_error_code(future_errc::future_already_retrieved)) - {} - }; - class BOOST_SYMBOL_VISIBLE promise_already_satisfied: - public future_error - { - public: - promise_already_satisfied(): - future_error(system::make_error_code(future_errc::promise_already_satisfied)) - {} - }; - - class BOOST_SYMBOL_VISIBLE task_already_started: - public future_error - { - public: - task_already_started(): - future_error(system::make_error_code(future_errc::promise_already_satisfied)) - {} - }; - - class BOOST_SYMBOL_VISIBLE task_moved: - public future_error - { - public: - task_moved(): - future_error(system::make_error_code(future_errc::no_state)) - {} - }; - - class promise_moved: - public future_error - { - public: - promise_moved(): - future_error(system::make_error_code(future_errc::no_state)) - {} - }; - - namespace future_state - { - enum state { uninitialized, waiting, ready, moved, deferred }; - } - namespace detail { struct relocker { boost::unique_lock<boost::mutex>& lock_; - bool unlocked_; relocker(boost::unique_lock<boost::mutex>& lk): lock_(lk) { lock_.unlock(); - unlocked_=true; } ~relocker() { - if (unlocked_) { + if (! lock_.owns_lock()) { lock_.lock(); } } void lock() { - if (unlocked_) { + if (! lock_.owns_lock()) { lock_.lock(); - unlocked_=false; } } private: @@ -220,36 +117,72 @@ namespace boost struct shared_state_base : enable_shared_from_this<shared_state_base> { typedef std::list<boost::condition_variable_any*> waiter_list; + typedef waiter_list::iterator notify_when_ready_handle; // This type should be only included conditionally if interruptions are allowed, but is included to maintain the same layout. typedef shared_ptr<shared_state_base> continuation_ptr_type; + typedef std::vector<continuation_ptr_type> continuations_type; boost::exception_ptr exception; bool done; + bool is_valid_; bool is_deferred_; - launch policy_; bool is_constructed; + std::size_t cnt_; + launch policy_; mutable boost::mutex mutex; boost::condition_variable waiters; waiter_list external_waiters; boost::function<void()> callback; // This declaration should be only included conditionally, but is included to maintain the same layout. - continuation_ptr_type continuation_ptr; + continuations_type continuations; // This declaration should be only included conditionally, but is included to maintain the same layout. - virtual void launch_continuation(boost::unique_lock<boost::mutex>&) + virtual void launch_continuation(boost::unique_lock<boost::mutex>&, shared_ptr<shared_state_base>) { } shared_state_base(): done(false), + is_valid_(true), is_deferred_(false), - policy_(launch::none), is_constructed(false), - continuation_ptr() + cnt_(0), + policy_(launch::none), + continuations() {} virtual ~shared_state_base() + { + BOOST_ASSERT(cnt_==0); + } + virtual void block_if_needed(boost::unique_lock<boost::mutex>&) {} + bool valid(boost::unique_lock<boost::mutex>&) { return is_valid_; } + bool valid() { + boost::unique_lock<boost::mutex> lk(this->mutex); + return valid(lk); + } + void invalidate(boost::unique_lock<boost::mutex>&) { is_valid_ = false; } + void invalidate() { + boost::unique_lock<boost::mutex> lk(this->mutex); + invalidate(lk); + } + void validate(boost::unique_lock<boost::mutex>&) { is_valid_ = true; } + void validate() { + boost::unique_lock<boost::mutex> lk(this->mutex); + validate(lk); + } + + void inc(boost::unique_lock<boost::mutex>&) { ++cnt_; } + void inc() { boost::unique_lock<boost::mutex> lk(this->mutex); inc(lk); } + + void dec(boost::unique_lock<boost::mutex>& lk) { + if (--cnt_ == 0) { + block_if_needed(lk); + } + } + void dec() { boost::unique_lock<boost::mutex> lk(this->mutex); dec(lk); } + void set_deferred() { is_deferred_ = true; @@ -267,14 +200,14 @@ namespace boost policy_ = launch::executor; } #endif - waiter_list::iterator register_external_waiter(boost::condition_variable_any& cv) + notify_when_ready_handle notify_when_ready(boost::condition_variable_any& cv) { boost::unique_lock<boost::mutex> lock(this->mutex); do_callback(lock); return external_waiters.insert(external_waiters.end(),&cv); } - void remove_external_waiter(waiter_list::iterator it) + void unnotify_when_ready(notify_when_ready_handle it) { boost::lock_guard<boost::mutex> lock(this->mutex); external_waiters.erase(it); @@ -283,10 +216,14 @@ namespace boost #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION void do_continuation(boost::unique_lock<boost::mutex>& lock) { - if (continuation_ptr) { - continuation_ptr_type this_continuation_ptr = continuation_ptr; - continuation_ptr.reset(); - this_continuation_ptr->launch_continuation(lock); + if (! continuations.empty()) { + continuations_type the_continuations = continuations; + continuations.clear(); + relocker rlk(lock); + for (continuations_type::iterator it = the_continuations.begin(); it != the_continuations.end(); ++it) { + boost::unique_lock<boost::mutex> cont_lock((*it)->mutex); + (*it)->launch_continuation(cont_lock, *it); + } } } #else @@ -295,9 +232,9 @@ namespace boost } #endif #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION - void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock<boost::mutex>& lock) + virtual void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock<boost::mutex>& lock) { - continuation_ptr= continuation; + continuations.push_back(continuation); if (done) { do_continuation(lock); } @@ -373,12 +310,17 @@ namespace boost } } - virtual void wait(bool rethrow=true) + virtual void wait(boost::unique_lock<boost::mutex>& lock, bool rethrow=true) { - boost::unique_lock<boost::mutex> lock(this->mutex); wait_internal(lock, rethrow); } + void wait(bool rethrow=true) + { + boost::unique_lock<boost::mutex> lock(this->mutex); + wait(lock, rethrow); + } + #if defined BOOST_THREAD_USES_DATETIME bool timed_wait_until(boost::system_time const& target_time) { @@ -431,27 +373,6 @@ namespace boost mark_exceptional_finish_internal(boost::current_exception(), lock); } -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - void mark_interrupted_finish() - { - boost::unique_lock<boost::mutex> lock(this->mutex); - exception = boost::copy_exception(boost::thread_interrupted()); - mark_finished_internal(lock); - } - - void set_interrupted_at_thread_exit() - { - unique_lock<boost::mutex> lk(this->mutex); - if (has_value(lk)) - { - throw_exception(promise_already_satisfied()); - } - exception = boost::copy_exception(boost::thread_interrupted()); - this->is_constructed = true; - detail::make_ready_at_thread_exit(shared_from_this()); - } -#endif - void set_exception_at_thread_exit(exception_ptr e) { unique_lock<boost::mutex> lk(this->mutex); @@ -481,20 +402,22 @@ namespace boost return done && exception; } - bool has_exception(unique_lock<boost::mutex>&) const - { - return done && exception; - } - - bool is_deferred(boost::lock_guard<boost::mutex>&) const { - return is_deferred_; - } - launch launch_policy(boost::unique_lock<boost::mutex>&) const { return policy_; } + future_state::state get_state(boost::unique_lock<boost::mutex>& lk) const + { + if(!done) + { + return future_state::waiting; + } + else + { + return future_state::ready; + } + } future_state::state get_state() const { boost::lock_guard<boost::mutex> guard(this->mutex); @@ -511,10 +434,6 @@ namespace boost exception_ptr get_exception_ptr() { boost::unique_lock<boost::mutex> lock(this->mutex); - return get_exception_ptr(lock); - } - exception_ptr get_exception_ptr(boost::unique_lock<boost::mutex>& lock) - { wait_internal(lock, false); return exception; } @@ -580,21 +499,29 @@ namespace boost void mark_finished_with_result_internal(rvalue_source_type result_, boost::unique_lock<boost::mutex>& lock) { -#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES #if defined BOOST_THREAD_FUTURE_USES_OPTIONAL result = boost::move(result_); -#else +#elif ! defined BOOST_NO_CXX11_RVALUE_REFERENCES result.reset(new T(boost::move(result_))); -#endif -#else -#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL - result = boost::move(result_); #else result.reset(new T(static_cast<rvalue_source_type>(result_))); #endif + this->mark_finished_internal(lock); + } + + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template <class ...Args> + void mark_finished_with_result_internal(boost::unique_lock<boost::mutex>& lock, BOOST_THREAD_FWD_REF(Args)... args) + { +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result.emplace(boost::forward<Args>(args)...); +#else + result.reset(new T(boost::forward<Args>(args)...)); #endif this->mark_finished_internal(lock); } +#endif void mark_finished_with_result(source_reference_type result_) { @@ -613,21 +540,29 @@ namespace boost #endif } - storage_type& get_storage(boost::unique_lock<boost::mutex>& lock) + storage_type& get_storage(boost::unique_lock<boost::mutex>& lk) { - wait_internal(lock); + wait_internal(lk); return result; } - virtual move_dest_type get() + virtual move_dest_type get(boost::unique_lock<boost::mutex>& lk) { - boost::unique_lock<boost::mutex> lock(this->mutex); - return boost::move(*get_storage(lock)); + return boost::move(*get_storage(lk)); + } + move_dest_type get() + { + boost::unique_lock<boost::mutex> lk(this->mutex); + return this->get(lk); } - virtual shared_future_get_result_type get_sh() + virtual shared_future_get_result_type get_sh(boost::unique_lock<boost::mutex>& lk) { - boost::unique_lock<boost::mutex> lock(this->mutex); - return *get_storage(lock); + return *get_storage(lk); + } + shared_future_get_result_type get_sh() + { + boost::unique_lock<boost::mutex> lk(this->mutex); + return this->get_sh(lk); } void set_value_at_thread_exit(source_reference_type result_) @@ -705,19 +640,27 @@ namespace boost mark_finished_with_result_internal(result_, lock); } - virtual T& get() + virtual T& get(boost::unique_lock<boost::mutex>& lock) { - boost::unique_lock<boost::mutex> lock(this->mutex); wait_internal(lock); return *result; } + T& get() + { + boost::unique_lock<boost::mutex> lk(this->mutex); + return get(lk); + } - virtual T& get_sh() + virtual T& get_sh(boost::unique_lock<boost::mutex>& lock) { - boost::unique_lock<boost::mutex> lock(this->mutex); wait_internal(lock); return *result; } + T& get_sh() + { + boost::unique_lock<boost::mutex> lock(this->mutex); + return get_sh(lock); + } void set_value_at_thread_exit(T& result_) { @@ -755,17 +698,25 @@ namespace boost mark_finished_with_result_internal(lock); } - virtual void get() + virtual void get(boost::unique_lock<boost::mutex>& lock) { - boost::unique_lock<boost::mutex> lock(this->mutex); this->wait_internal(lock); } - - virtual void get_sh() + void get() { boost::unique_lock<boost::mutex> lock(this->mutex); + this->get(lock); + } + + virtual void get_sh(boost::unique_lock<boost::mutex>& lock) + { this->wait_internal(lock); } + void get_sh() + { + boost::unique_lock<boost::mutex> lock(this->mutex); + this->get_sh(lock); + } void set_value_at_thread_exit() { @@ -801,15 +752,23 @@ namespace boost this->set_async(); } + virtual void block_if_needed(boost::unique_lock<boost::mutex>& lk) + { + this->wait(lk, false); + } + ~future_async_shared_state_base() { join(); } - virtual void wait(bool rethrow) + virtual void wait(boost::unique_lock<boost::mutex>& lk, bool rethrow) { - join(); - this->base_type::wait(rethrow); + { + relocker rlk(lk); + join(); + } + this->base_type::wait(lk, rethrow); } }; @@ -819,23 +778,23 @@ namespace boost template<typename Rp, typename Fp> struct future_async_shared_state: future_async_shared_state_base<Rp> { - explicit future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) + future_async_shared_state() + { + } + + void init(BOOST_THREAD_FWD_REF(Fp) f) { - this->thr_ = thread(&future_async_shared_state::run, this, boost::forward<Fp>(f)); + shared_ptr<boost::detail::shared_state_base> that = this->shared_from_this(); + this->thr_ = thread(&future_async_shared_state::run, that, boost::forward<Fp>(f)); } - static void run(future_async_shared_state* that, BOOST_THREAD_FWD_REF(Fp) f) + static void run(shared_ptr<boost::detail::shared_state_base> that_, BOOST_THREAD_FWD_REF(Fp) f) { + future_async_shared_state* that = dynamic_cast<future_async_shared_state*>(that_.get()); try { that->mark_finished_with_result(f()); } -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - that->mark_interrupted_finish(); - } -#endif catch(...) { that->mark_exceptional_finish(); @@ -846,24 +805,19 @@ namespace boost template<typename Fp> struct future_async_shared_state<void, Fp>: public future_async_shared_state_base<void> { - explicit future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) + void init(BOOST_THREAD_FWD_REF(Fp) f) { - this->thr_ = thread(&future_async_shared_state::run, this, boost::move(f)); + this->thr_ = thread(&future_async_shared_state::run, this->shared_from_this(), boost::move(f)); } - static void run(future_async_shared_state* that, BOOST_THREAD_FWD_REF(Fp) f) + static void run(shared_ptr<boost::detail::shared_state_base> that_, BOOST_THREAD_FWD_REF(Fp) f) { + future_async_shared_state* that = dynamic_cast<future_async_shared_state*>(that_.get()); try { f(); that->mark_finished_with_result(); } -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - that->mark_interrupted_finish(); - } -#endif catch(...) { that->mark_exceptional_finish(); @@ -874,23 +828,18 @@ namespace boost template<typename Rp, typename Fp> struct future_async_shared_state<Rp&, Fp>: future_async_shared_state_base<Rp&> { - explicit future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) + void init(BOOST_THREAD_FWD_REF(Fp) f) { - this->thr_ = thread(&future_async_shared_state::run, this, boost::move(f)); + this->thr_ = thread(&future_async_shared_state::run, this->shared_from_this(), boost::move(f)); } - static void run(future_async_shared_state* that, BOOST_THREAD_FWD_REF(Fp) f) + static void run(shared_ptr<boost::detail::shared_state_base> that_, BOOST_THREAD_FWD_REF(Fp) f) { + future_async_shared_state* that = dynamic_cast<future_async_shared_state*>(that_.get()); try { that->mark_finished_with_result(f()); } -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - that->mark_interrupted_finish(); - } -#endif catch(...) { that->mark_exceptional_finish(); @@ -991,13 +940,13 @@ namespace boost struct registered_waiter { boost::shared_ptr<detail::shared_state_base> future_; - detail::shared_state_base::waiter_list::iterator wait_iterator; + detail::shared_state_base::notify_when_ready_handle handle; count_type index; registered_waiter(boost::shared_ptr<detail::shared_state_base> const& a_future, - detail::shared_state_base::waiter_list::iterator wait_iterator_, + detail::shared_state_base::notify_when_ready_handle handle_, count_type index_): - future_(a_future),wait_iterator(wait_iterator_),index(index_) + future_(a_future),handle(handle_),index(index_) {} }; @@ -1035,7 +984,7 @@ namespace boost }; boost::condition_variable_any cv; - std::vector<registered_waiter> futures; + std::vector<registered_waiter> futures_; count_type future_count; public: @@ -1048,11 +997,11 @@ namespace boost { if(f.future_) { - registered_waiter waiter(f.future_,f.future_->register_external_waiter(cv),future_count); + registered_waiter waiter(f.future_,f.future_->notify_when_ready(cv),future_count); try { - futures.push_back(waiter); + futures_.push_back(waiter); } catch(...) { - f.future_->remove_external_waiter(waiter.wait_iterator); + f.future_->unnotify_when_ready(waiter.handle); throw; } } @@ -1069,14 +1018,14 @@ namespace boost count_type wait() { - all_futures_lock lk(futures); + all_futures_lock lk(futures_); for(;;) { - for(count_type i=0;i<futures.size();++i) + for(count_type i=0;i<futures_.size();++i) { - if(futures[i].future_->done) + if(futures_[i].future_->done) { - return futures[i].index; + return futures_[i].index; } } cv.wait(lk); @@ -1085,9 +1034,9 @@ namespace boost ~future_waiter() { - for(count_type i=0;i<futures.size();++i) + for(count_type i=0;i<futures_.size();++i) { - futures[i].future_->remove_external_waiter(futures[i].wait_iterator); + futures_[i].future_->unnotify_when_ready(futures_[i].handle); } } }; @@ -1101,93 +1050,28 @@ namespace boost class shared_future; template<typename T> - struct is_future_type - { - BOOST_STATIC_CONSTANT(bool, value=false); - typedef void type; - }; - - template<typename T> - struct is_future_type<BOOST_THREAD_FUTURE<T> > + struct is_future_type<BOOST_THREAD_FUTURE<T> > : true_type { - BOOST_STATIC_CONSTANT(bool, value=true); - typedef T type; }; template<typename T> - struct is_future_type<shared_future<T> > + struct is_future_type<shared_future<T> > : true_type { - BOOST_STATIC_CONSTANT(bool, value=true); - typedef T type; }; - template<typename Iterator> - typename boost::disable_if<is_future_type<Iterator>,void>::type wait_for_all(Iterator begin,Iterator end) - { - for(Iterator current=begin;current!=end;++current) - { - current->wait(); - } - } - -#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES - template<typename F1,typename F2> - typename boost::enable_if<is_future_type<F1>,void>::type wait_for_all(F1& f1,F2& f2) - { - f1.wait(); - f2.wait(); - } - - template<typename F1,typename F2,typename F3> - void wait_for_all(F1& f1,F2& f2,F3& f3) - { - f1.wait(); - f2.wait(); - f3.wait(); - } - - template<typename F1,typename F2,typename F3,typename F4> - void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4) - { - f1.wait(); - f2.wait(); - f3.wait(); - f4.wait(); - } - - template<typename F1,typename F2,typename F3,typename F4,typename F5> - void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5) - { - f1.wait(); - f2.wait(); - f3.wait(); - f4.wait(); - f5.wait(); - } -#else - template<typename F1, typename... Fs> - void wait_for_all(F1& f1, Fs&... fs) - { - bool dummy[] = { (f1.wait(), true), (fs.wait(), true)... }; - - // prevent unused parameter warning - (void) dummy; - } -#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - template<typename Iterator> - typename boost::disable_if<is_future_type<Iterator>,Iterator>::type wait_for_any(Iterator begin,Iterator end) - { - if(begin==end) - return end; - - detail::future_waiter waiter; - for(Iterator current=begin;current!=end;++current) - { - waiter.add(*current); - } - return boost::next(begin,waiter.wait()); - } +// template<typename Iterator> +// typename boost::disable_if<is_future_type<Iterator>,Iterator>::type wait_for_any(Iterator begin,Iterator end) +// { +// if(begin==end) +// return end; +// +// detail::future_waiter waiter; +// for(Iterator current=begin;current!=end;++current) +// { +// waiter.add(*current); +// } +// return boost::next(begin,waiter.wait()); +// } #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES template<typename F1,typename F2> @@ -1252,6 +1136,7 @@ namespace boost /// Common implementation for all the futures independently of the return type class base_future { + public: }; /// Common implementation for future and shared_future. template <typename R> @@ -1277,15 +1162,13 @@ namespace boost future_ = p.get_future().future_; } - future_ptr future_; basic_future(future_ptr a_future): future_(a_future) { + if (a_future) a_future->inc(); } - // Copy construction from a shared_future - explicit basic_future(const shared_future<R>&) BOOST_NOEXCEPT; public: typedef future_state::state state; @@ -1298,9 +1181,12 @@ namespace boost basic_future(exceptional_ptr const& ex) : future_(make_exceptional_future_ptr(ex)) { + future_->inc(); } - ~basic_future() {} + ~basic_future() { + if (future_) future_->dec(); + } basic_future(BOOST_THREAD_RV_REF(basic_future) other) BOOST_NOEXCEPT: future_(BOOST_THREAD_RV(other).future_) @@ -1309,6 +1195,9 @@ namespace boost } basic_future& operator=(BOOST_THREAD_RV_REF(basic_future) other) BOOST_NOEXCEPT { + if (this->future_) { + this->future_->dec(); + } future_=BOOST_THREAD_RV(other).future_; BOOST_THREAD_RV(other).future_.reset(); return *this; @@ -1318,6 +1207,14 @@ namespace boost future_.swap(that.future_); } // functions to check state, and wait for ready + state get_state(boost::unique_lock<boost::mutex>& lk) const + { + if(!future_) + { + return future_state::uninitialized; + } + return future_->get_state(lk); + } state get_state() const { if(!future_) @@ -1332,6 +1229,10 @@ namespace boost return get_state()==future_state::ready; } + bool is_ready(boost::unique_lock<boost::mutex>& lk) const + { + return get_state(lk)==future_state::ready; + } bool has_exception() const { return future_ && future_->has_exception(); @@ -1357,7 +1258,7 @@ namespace boost bool valid() const BOOST_NOEXCEPT { - return future_ != 0; + return future_ != 0 && future_->valid(); } void wait() const @@ -1369,6 +1270,34 @@ namespace boost future_->wait(false); } + typedef detail::shared_state_base::notify_when_ready_handle notify_when_ready_handle; + + boost::mutex& mutex() { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->mutex; + }; + + notify_when_ready_handle notify_when_ready(boost::condition_variable_any& cv) + { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->notify_when_ready(cv); + } + + void unnotify_when_ready(notify_when_ready_handle h) + { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->unnotify_when_ready(h); + } + #if defined BOOST_THREAD_USES_DATETIME template<typename Duration> bool timed_wait(Duration const& rel_time) const @@ -1516,6 +1445,10 @@ namespace boost } inline BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R> >) other); // EXTENSION + explicit BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(shared_future<R>) other) : + base_type(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other)))) + {} + BOOST_THREAD_FUTURE& operator=(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT { this->base_type::operator=(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other)))); @@ -1551,32 +1484,42 @@ namespace boost // retrieving the value move_dest_type get() { - if(!this->future_) + if (this->future_ == 0) + { + boost::throw_exception(future_uninitialized()); + } + unique_lock<boost::mutex> lk(this->future_->mutex); + if (! this->future_->valid(lk)) { boost::throw_exception(future_uninitialized()); } - future_ptr fut_=this->future_; #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET - this->future_.reset(); + this->future_->invalidate(lk); #endif - return fut_->get(); + return this->future_->get(lk); } template <typename R2> typename boost::disable_if< is_void<R2>, move_dest_type>::type get_or(BOOST_THREAD_RV_REF(R2) v) { - if(!this->future_) + + if (this->future_ == 0) + { + boost::throw_exception(future_uninitialized()); + } + unique_lock<boost::mutex> lk(this->future_->mutex); + if (! this->future_->valid(lk)) { boost::throw_exception(future_uninitialized()); } - this->future_->wait(false); - future_ptr fut_=this->future_; + this->future_->wait(lk, false); #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET - this->future_.reset(); + this->future_->invalidate(lk); #endif - if (fut_->has_value()) { - return fut_->get(); + + if (this->future_->has_value(lk)) { + return this->future_->get(lk); } else { return boost::move(v); @@ -1587,17 +1530,21 @@ namespace boost typename boost::disable_if< is_void<R2>, move_dest_type>::type get_or(R2 const& v) // EXTENSION { - if(!this->future_) + if (this->future_ == 0) { boost::throw_exception(future_uninitialized()); } - this->future_->wait(false); - future_ptr fut_=this->future_; + unique_lock<boost::mutex> lk(this->future_->mutex); + if (! this->future_->valid(lk)) + { + boost::throw_exception(future_uninitialized()); + } + this->future_->wait(lk, false); #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET - this->future_.reset(); + this->future_->invalidate(lk); #endif - if (fut_->has_value()) { - return fut_->get(); + if (this->future_->has_value(lk)) { + return this->future_->get(lk); } else { return v; @@ -1736,43 +1683,55 @@ namespace boost // retrieving the value move_dest_type get() { - if(!this->future_) + if (this->future_ == 0) + { + boost::throw_exception(future_uninitialized()); + } + unique_lock<boost::mutex> lk(this->future_->mutex); + if (! this->future_->valid(lk)) { boost::throw_exception(future_uninitialized()); } - future_ptr fut_=this->future_; #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET - this->future_.reset(); + this->future_->invalidate(lk); #endif - return fut_->get(); + return this->future_->get(lk); } move_dest_type get_or(BOOST_THREAD_RV_REF(R) v) // EXTENSION { - if(!this->future_) + if (this->future_ == 0) { boost::throw_exception(future_uninitialized()); } - this->future_->wait(false); - future_ptr fut_=this->future_; + unique_lock<boost::mutex> lk(this->future_->mutex); + if (! this->future_->valid(lk)) + { + boost::throw_exception(future_uninitialized()); + } + this->future_->wait(lk, false); #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET - this->future_.reset(); + this->future_->invalidate(lk); #endif - if (fut_->has_value()) return fut_->get(); + if (this->future_->has_value(lk)) return this->future_->get(lk); else return boost::move(v); } move_dest_type get_or(R const& v) // EXTENSION { - if(!this->future_) + if (this->future_ == 0) { boost::throw_exception(future_uninitialized()); } - this->future_->wait(false); - future_ptr fut_=this->future_; + unique_lock<boost::mutex> lk(this->future_->mutex); + if (! this->future_->valid(lk)) + { + boost::throw_exception(future_uninitialized()); + } + this->future_->wait(lk, false); #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET - this->future_.reset(); + this->future_->invalidate(lk); #endif - if (fut_->has_value()) return fut_->get(); + if (this->future_->has_value(lk)) return this->future_->get(lk); else return v; } @@ -1836,7 +1795,7 @@ namespace boost typedef R value_type; // EXTENSION shared_future(shared_future const& other): - base_type(other) + base_type(other.future_) {} typedef future_state::state state; @@ -1851,14 +1810,19 @@ namespace boost shared_future& operator=(BOOST_THREAD_COPY_ASSIGN_REF(shared_future) other) { - shared_future(other).swap(*this); + if (other.future_) { + other.future_->inc(); + } + if (this->future_) { + this->future_->dec(); + } + this->future_ = other.future_; return *this; } shared_future(BOOST_THREAD_RV_REF(shared_future) other) BOOST_NOEXCEPT : base_type(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other)))) { - BOOST_THREAD_RV(other).future_.reset(); } shared_future(BOOST_THREAD_RV_REF( BOOST_THREAD_FUTURE<R> ) other) BOOST_NOEXCEPT : base_type(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other)))) @@ -1887,7 +1851,7 @@ namespace boost return this->future_->run_if_is_deferred_or_ready(); } // retrieving the value - typename detail::shared_state<R>::shared_future_get_result_type get() + typename detail::shared_state<R>::shared_future_get_result_type get() const { if(!this->future_) { @@ -1898,15 +1862,14 @@ namespace boost template <typename R2> typename boost::disable_if< is_void<R2>, typename detail::shared_state<R>::shared_future_get_result_type>::type - get_or(BOOST_THREAD_RV_REF(R2) v) // EXTENSION + get_or(BOOST_THREAD_RV_REF(R2) v) const // EXTENSION { if(!this->future_) { boost::throw_exception(future_uninitialized()); } - future_ptr fut_=this->future_; - fut_->wait(); - if (fut_->has_value()) return fut_->get_sh(); + this->future_->wait(); + if (this->future_->has_value()) return this->future_->get_sh(); else return boost::move(v); } @@ -1928,16 +1891,6 @@ namespace boost BOOST_THREAD_DCL_MOVABLE_BEG(T) shared_future<T> BOOST_THREAD_DCL_MOVABLE_END - namespace detail - { - /// Copy construction from a shared_future - template <typename R> - inline basic_future<R>::basic_future(const shared_future<R>& other) BOOST_NOEXCEPT - : future_(other.future_) - { - } - } - template <typename R> class promise { @@ -2077,6 +2030,22 @@ namespace boost future_->mark_finished_with_result_internal(static_cast<rvalue_source_type>(r), lock); #endif } + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template <class ...Args> + void emplace(BOOST_THREAD_FWD_REF(Args) ...args) + { + lazy_init(); + boost::unique_lock<boost::mutex> lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_finished_with_result_internal(lock, boost::forward<Args>(args)...); + } + +#endif + void set_exception(boost::exception_ptr p) { lazy_init(); @@ -2503,7 +2472,10 @@ namespace boost void reset() { + // todo The packaged_task::reset must be as if an assignemnt froma new packaged_task with the same function + // the reset function is an optimization that avoids reallocating a new task. started=false; + this->validate(); } #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) virtual void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args)=0; @@ -2591,6 +2563,11 @@ namespace boost f(boost::move(f_)) {} + F callable() + { + return boost::move(f); + } + #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) { @@ -2606,12 +2583,6 @@ namespace boost this->set_value_at_thread_exit(f()); } #endif -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - this->set_interrupted_at_thread_exit(); - } -#endif catch(...) { this->set_exception_at_thread_exit(current_exception()); @@ -2638,12 +2609,6 @@ namespace boost #endif } #endif -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - this->mark_interrupted_finish(); - } -#endif catch(...) { this->mark_exceptional_finish(); @@ -2678,6 +2643,11 @@ namespace boost f(boost::move(f_)) {} + F callable() + { + return f; + } + #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) { @@ -2693,12 +2663,6 @@ namespace boost this->set_value_at_thread_exit(f()); } #endif -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - this->set_interrupted_at_thread_exit(); - } -#endif catch(...) { this->set_exception_at_thread_exit(current_exception()); @@ -2721,12 +2685,6 @@ namespace boost this->mark_finished_with_result(res); } #endif -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - this->mark_interrupted_finish(); - } -#endif catch(...) { this->mark_exceptional_finish(); @@ -2754,18 +2712,21 @@ namespace boost { private: task_shared_state(task_shared_state&); - public: #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) - R (*f)(BOOST_THREAD_RV_REF(ArgTypes) ... ); - task_shared_state(R (*f_)(BOOST_THREAD_RV_REF(ArgTypes) ... )): - f(f_) - {} + typedef R (*CallableType)(BOOST_THREAD_RV_REF(ArgTypes) ... ); #else - R (*f)(); - task_shared_state(R (*f_)()): + typedef R (*CallableType)(); +#endif + public: + CallableType f; + task_shared_state(CallableType f_): f(f_) {} -#endif + + CallableType callable() + { + return f; + } #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) @@ -2783,12 +2744,6 @@ namespace boost this->set_value_at_thread_exit(boost::move(r)); } #endif -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - this->set_interrupted_at_thread_exit(); - } -#endif catch(...) { this->set_exception_at_thread_exit(current_exception()); @@ -2812,12 +2767,6 @@ namespace boost this->mark_finished_with_result(boost::move(res)); } #endif -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - this->mark_interrupted_finish(); - } -#endif catch(...) { this->mark_exceptional_finish(); @@ -2844,16 +2793,19 @@ namespace boost task_shared_state(task_shared_state&); public: #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) - R& (*f)(BOOST_THREAD_RV_REF(ArgTypes) ... ); - task_shared_state(R& (*f_)(BOOST_THREAD_RV_REF(ArgTypes) ... )): - f(f_) - {} + typedef R& (*CallableType)(BOOST_THREAD_RV_REF(ArgTypes) ... ); #else - R& (*f)(); - task_shared_state(R& (*f_)()): + typedef R& (*CallableType)(); +#endif + CallableType f; + task_shared_state(CallableType f_): f(f_) {} -#endif + + CallableType callable() + { + return boost::move(f); + } #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) @@ -2870,12 +2822,6 @@ namespace boost this->set_value_at_thread_exit(f()); } #endif -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - this->set_interrupted_at_thread_exit(); - } -#endif catch(...) { this->set_exception_at_thread_exit(current_exception()); @@ -2898,12 +2844,6 @@ namespace boost this->mark_finished_with_result(f()); } #endif -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - this->mark_interrupted_finish(); - } -#endif catch(...) { this->mark_exceptional_finish(); @@ -2930,6 +2870,7 @@ namespace boost private: task_shared_state(task_shared_state&); public: + typedef F CallableType; F f; task_shared_state(F const& f_): f(f_) @@ -2937,7 +2878,10 @@ namespace boost task_shared_state(BOOST_THREAD_RV_REF(F) f_): f(boost::move(f_)) {} - + F callable() + { + return boost::move(f); + } #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) { @@ -2953,12 +2897,6 @@ namespace boost #endif this->set_value_at_thread_exit(); } -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - this->set_interrupted_at_thread_exit(); - } -#endif catch(...) { this->set_exception_at_thread_exit(current_exception()); @@ -2980,12 +2918,6 @@ namespace boost #endif this->mark_finished_with_result(); } -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - this->mark_interrupted_finish(); - } -#endif catch(...) { this->mark_exceptional_finish(); @@ -3011,12 +2943,20 @@ namespace boost { private: task_shared_state(task_shared_state&); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef void (*CallableType)(BOOST_THREAD_RV_REF(ArgTypes)...); +#else + typedef void (*CallableType)(); +#endif public: - void (*f)(); - task_shared_state(void (*f_)()): + CallableType f; + task_shared_state(CallableType f_): f(f_) {} - + CallableType callable() + { + return f; + } #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) { @@ -3032,12 +2972,6 @@ namespace boost #endif this->set_value_at_thread_exit(); } -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - this->set_interrupted_at_thread_exit(); - } -#endif catch(...) { this->set_exception_at_thread_exit(current_exception()); @@ -3059,12 +2993,6 @@ namespace boost #endif this->mark_finished_with_result(); } -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - catch(thread_interrupted& ) - { - this->mark_interrupted_finish(); - } -#endif catch(...) { this->mark_exceptional_finish(); @@ -3277,11 +3205,7 @@ namespace boost A2 a2(a); typedef thread_detail::allocator_destructor<A2> D; -#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(boost::move(f)), D(a2, 1) ); -#else - task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(boost::move(f)), D(a2, 1) ); -#endif future_obtained = false; } @@ -3314,6 +3238,9 @@ namespace boost void reset() { if (!valid()) throw future_error(system::make_error_code(future_errc::no_state)); + + // As if *this = packaged_task(task->callable()); + task->reset(); future_obtained=false; } @@ -3415,7 +3342,8 @@ namespace detail BOOST_THREAD_FUTURE<Rp> make_future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) { shared_ptr<future_async_shared_state<Rp, Fp> > - h(new future_async_shared_state<Rp, Fp>(boost::forward<Fp>(f))); + h(new future_async_shared_state<Rp, Fp>()); + h->init(boost::forward<Fp>(f)); return BOOST_THREAD_FUTURE<Rp>(h); } } @@ -3602,10 +3530,6 @@ namespace detail { void operator()() { try { that->mark_finished_with_result(f_()); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif // defined BOOST_THREAD_PROVIDES_INTERRUPTIONS } catch(...) { that->mark_exceptional_finish(); } @@ -3653,10 +3577,6 @@ namespace detail { try { f_(); that->mark_finished_with_result(); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif // defined BOOST_THREAD_PROVIDES_INTERRUPTIONS } catch(...) { that->mark_exceptional_finish(); } @@ -3702,10 +3622,6 @@ namespace detail { void operator()() { try { that->mark_finished_with_result(f_()); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif // defined BOOST_THREAD_PROVIDES_INTERRUPTIONS } catch(...) { that->mark_exceptional_finish(); } @@ -3728,9 +3644,12 @@ namespace detail { ex.submit(boost::move(t)); } - ~future_executor_shared_state() { - this->wait(false); + virtual void block_if_needed(boost::unique_lock<boost::mutex>&lk) + { + this->wait(lk, false); } + + ~future_executor_shared_state() {} }; //////////////////////////////// @@ -3929,14 +3848,80 @@ namespace detail { //////////////////////////////// // make_ready_future //////////////////////////////// - template <typename T> - BOOST_THREAD_FUTURE<typename decay<T>::type> make_ready_future(BOOST_THREAD_FWD_REF(T) value) { - typedef typename decay<T>::type future_value_type; + namespace detail { + template <class T> + struct deduced_type_impl + { + typedef T type; + }; + + template <class T> + struct deduced_type_impl<reference_wrapper<T> const> + { + typedef T& type; + }; + template <class T> + struct deduced_type_impl<reference_wrapper<T> > + { + typedef T& type; + }; +#if __cplusplus > 201103L + template <class T> + struct deduced_type_impl<std::reference_wrapper<T> > + { + typedef T& type; + }; +#endif + template <class T> + struct deduced_type + { + typedef typename detail::deduced_type_impl<typename decay<T>::type>::type type; + }; + + } + + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template <int = 0, int..., class T> +#else + template <class T> +#endif + BOOST_THREAD_FUTURE<typename detail::deduced_type<T>::type> make_ready_future(BOOST_THREAD_FWD_REF(T) value) { + typedef typename detail::deduced_type<T>::type future_value_type; promise<future_value_type> p; - p.set_value(boost::forward<future_value_type>(value)); + p.set_value(boost::forward<T>(value)); return BOOST_THREAD_MAKE_RV_REF(p.get_future()); } + // explicit overloads + template <class T> + BOOST_THREAD_FUTURE<T> make_ready_future(typename remove_reference<T>::type & x) + { + promise<T> p; + p.set_value(x); + return p.get_future(); + } + + template <class T> + BOOST_THREAD_FUTURE<T> make_ready_future(BOOST_THREAD_FWD_REF(typename remove_reference<T>::type) x) + { + promise<T> p; + p.set_value(forward<typename remove_reference<T>::type>(x)); + return p.get_future(); + } + + // variadic overload +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template <class T, class ...Args> + BOOST_THREAD_FUTURE<T> make_ready_future(Args&&... args) + { + promise<T> p; + p.emplace(forward<Args>(args)...); + return p.get_future(); + + } +#endif + template <typename T, typename T1> BOOST_THREAD_FUTURE<T> make_ready_no_decay_future(T1 value) { typedef T future_value_type; @@ -3945,11 +3930,11 @@ namespace detail { return BOOST_THREAD_MAKE_RV_REF(p.get_future()); } -#if defined BOOST_THREAD_USES_MOVE +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined BOOST_THREAD_USES_MOVE inline BOOST_THREAD_FUTURE<void> make_ready_future() { promise<void> p; p.set_value(); - return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + return p.get_future(); } #endif @@ -4038,31 +4023,30 @@ namespace detail { F parent; Fp continuation; + shared_ptr<shared_state_base> centinel; public: future_async_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) : parent(boost::move(f)), - continuation(boost::move(c)) { + continuation(boost::move(c)), + centinel(parent.future_) { } - void launch_continuation(boost::unique_lock<boost::mutex>& ) { - this->thr_ = thread(&future_async_continuation_shared_state::run, this); + + void launch_continuation(boost::unique_lock<boost::mutex>&, shared_ptr<shared_state_base> that) { + this->thr_ = thread(&future_async_continuation_shared_state::run, that); } - static void run(future_async_continuation_shared_state* that) { + static void run(shared_ptr<boost::detail::shared_state_base> that_) { + future_async_continuation_shared_state* that = dynamic_cast<future_async_continuation_shared_state*>(that_.get()); try { that->mark_finished_with_result(that->continuation(boost::move(that->parent))); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif } catch(...) { that->mark_exceptional_finish(); } } ~future_async_continuation_shared_state() { - this->join(); } }; @@ -4071,33 +4055,31 @@ namespace detail { F parent; Fp continuation; + shared_ptr<shared_state_base> centinel; public: future_async_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) : parent(boost::move(f)), - continuation(boost::move(c)) { + continuation(boost::move(c)), + centinel(parent.future_) { } - void launch_continuation(boost::unique_lock<boost::mutex>& ) { - this->thr_ = thread(&future_async_continuation_shared_state::run, this); + void launch_continuation(boost::unique_lock<boost::mutex>&, shared_ptr<shared_state_base> that) { + this->thr_ = thread(&future_async_continuation_shared_state::run, that); } - static void run(future_async_continuation_shared_state* that) { + static void run(shared_ptr<boost::detail::shared_state_base> that_) { + future_async_continuation_shared_state* that = dynamic_cast<future_async_continuation_shared_state*>(that_.get()); try { that->continuation(boost::move(that->parent)); that->mark_finished_with_result(); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif } catch(...) { that->mark_exceptional_finish(); } } - ~future_async_continuation_shared_state() { - this->join(); - } + ~future_async_continuation_shared_state() {} + }; ///////////////////////// @@ -4105,12 +4087,16 @@ namespace detail ///////////////////////// #ifdef BOOST_THREAD_PROVIDES_EXECUTORS - template <typename Ex> + template <typename FutureExecutorContinuationSharedState> struct run_it { - Ex* that; + shared_ptr<boost::detail::shared_state_base> that_; - run_it(Ex* that) : that (that) {} - void operator()() { that->run(that); } + run_it(shared_ptr<boost::detail::shared_state_base> that) : that_ (that) {} + void operator()() + { + FutureExecutorContinuationSharedState* that = dynamic_cast<FutureExecutorContinuationSharedState*>(that_.get()); + that->run(that_); + } }; template<typename Ex, typename F, typename Rp, typename Fp> @@ -4119,34 +4105,37 @@ namespace detail Ex* ex; F parent; Fp continuation; + shared_ptr<shared_state_base> centinel; public: future_executor_continuation_shared_state(Ex& ex, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) : ex(&ex), parent(boost::move(f)), - continuation(boost::move(c)) { + continuation(boost::move(c)), + centinel(parent.future_) { this->set_executor(); } - void launch_continuation(boost::unique_lock<boost::mutex>& ) { - run_it<future_executor_continuation_shared_state> fct(this); + void launch_continuation(boost::unique_lock<boost::mutex>& lck, shared_ptr<shared_state_base> that ) { + relocker relock(lck); + run_it<future_executor_continuation_shared_state> fct(that); ex->submit(fct); } - static void run(future_executor_continuation_shared_state* that) { + static void run(shared_ptr<boost::detail::shared_state_base> that_) { + future_executor_continuation_shared_state* that = dynamic_cast<future_executor_continuation_shared_state*>(that_.get()); try { that->mark_finished_with_result(that->continuation(boost::move(that->parent))); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif } catch(...) { that->mark_exceptional_finish(); } } - ~future_executor_continuation_shared_state() { - this->wait(false); + virtual void block_if_needed(boost::unique_lock<boost::mutex>&lk) + { + this->wait(lk, false); } + + ~future_executor_continuation_shared_state() {} }; template<typename Ex, typename F, typename Fp> @@ -4155,35 +4144,38 @@ namespace detail Ex* ex; F parent; Fp continuation; + shared_ptr<shared_state_base> centinel; public: future_executor_continuation_shared_state(Ex& ex, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) : ex(&ex), parent(boost::move(f)), - continuation(boost::move(c)) { + continuation(boost::move(c)), + centinel(parent.future_) { this->set_executor(); } - void launch_continuation(boost::unique_lock<boost::mutex>& ) { - run_it<future_executor_continuation_shared_state> fct(this); + void launch_continuation(boost::unique_lock<boost::mutex>& lck, shared_ptr<shared_state_base> that ) { + relocker relock(lck); + run_it<future_executor_continuation_shared_state> fct(that); ex->submit(fct); } - static void run(future_executor_continuation_shared_state* that) { + static void run(shared_ptr<boost::detail::shared_state_base> that_) { + future_executor_continuation_shared_state* that = dynamic_cast<future_executor_continuation_shared_state*>(that_.get()); try { that->continuation(boost::move(that->parent)); that->mark_finished_with_result(); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif } catch(...) { that->mark_exceptional_finish(); } } - ~future_executor_continuation_shared_state() { - this->wait(false); + virtual void block_if_needed(boost::unique_lock<boost::mutex>&lk) + { + this->wait(lk, false); } + + ~future_executor_continuation_shared_state() {} }; #endif @@ -4196,32 +4188,29 @@ namespace detail { F parent; Fp continuation; + shared_ptr<shared_state_base> centinel; public: shared_future_async_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) : parent(f), - continuation(boost::move(c)) { + continuation(boost::move(c)), + centinel(parent.future_) { } - void launch_continuation(boost::unique_lock<boost::mutex>& ) { - this->thr_ = thread(&shared_future_async_continuation_shared_state::run, this); + void launch_continuation(boost::unique_lock<boost::mutex>&, shared_ptr<shared_state_base> that) { + this->thr_ = thread(&shared_future_async_continuation_shared_state::run, that); } - static void run(shared_future_async_continuation_shared_state* that) { + static void run(shared_ptr<boost::detail::shared_state_base> that_) { + shared_future_async_continuation_shared_state* that = dynamic_cast<shared_future_async_continuation_shared_state*>(that_.get()); try { that->mark_finished_with_result(that->continuation(that->parent)); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif } catch(...) { that->mark_exceptional_finish(); } } - ~shared_future_async_continuation_shared_state() { - this->join(); - } + ~shared_future_async_continuation_shared_state() {} }; template<typename F, typename Fp> @@ -4229,33 +4218,30 @@ namespace detail { F parent; Fp continuation; + shared_ptr<shared_state_base> centinel; public: shared_future_async_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) : parent(f), - continuation(boost::move(c)) { + continuation(boost::move(c)), + centinel(parent.future_) { } - void launch_continuation(boost::unique_lock<boost::mutex>& ) { - this->thr_ = thread(&shared_future_async_continuation_shared_state::run, this); + void launch_continuation(boost::unique_lock<boost::mutex>&, shared_ptr<shared_state_base> that) { + this->thr_ = thread(&shared_future_async_continuation_shared_state::run, that); } - static void run(shared_future_async_continuation_shared_state* that) { + static void run(shared_ptr<boost::detail::shared_state_base> that_) { + shared_future_async_continuation_shared_state* that = dynamic_cast<shared_future_async_continuation_shared_state*>(that_.get()); try { that->continuation(that->parent); that->mark_finished_with_result(); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif } catch(...) { that->mark_exceptional_finish(); } } - ~shared_future_async_continuation_shared_state() { - this->join(); - } + ~shared_future_async_continuation_shared_state() {} }; ///////////////////////// @@ -4269,34 +4255,37 @@ namespace detail Ex* ex; F parent; Fp continuation; + shared_ptr<shared_state_base> centinel; public: shared_future_executor_continuation_shared_state(Ex& ex, F f, BOOST_THREAD_FWD_REF(Fp) c) : ex(&ex), parent(f), - continuation(boost::move(c)) { + continuation(boost::move(c)), + centinel(parent.future_) { this->set_executor(); } - void launch_continuation(boost::unique_lock<boost::mutex>& ) { - run_it<shared_future_executor_continuation_shared_state> fct(this); + void launch_continuation(boost::unique_lock<boost::mutex>& lck, shared_ptr<shared_state_base> that) { + relocker relock(lck); + run_it<shared_future_executor_continuation_shared_state> fct(that); ex->submit(fct); } - static void run(shared_future_executor_continuation_shared_state* that) { + static void run(shared_ptr<boost::detail::shared_state_base> that_) { + shared_future_executor_continuation_shared_state* that = dynamic_cast<shared_future_executor_continuation_shared_state*>(that_.get()); try { that->mark_finished_with_result(that->continuation(that->parent)); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif } catch(...) { that->mark_exceptional_finish(); } } - ~shared_future_executor_continuation_shared_state() { - this->wait(false); + virtual void block_if_needed(boost::unique_lock<boost::mutex>&lk) + { + this->wait(lk, false); } + + ~shared_future_executor_continuation_shared_state() {} }; template<typename Ex, typename F, typename Fp> @@ -4305,34 +4294,37 @@ namespace detail Ex* ex; F parent; Fp continuation; + shared_ptr<shared_state_base> centinel; public: shared_future_executor_continuation_shared_state(Ex& ex, F f, BOOST_THREAD_FWD_REF(Fp) c) : ex(&ex), parent(f), - continuation(boost::move(c)) { + continuation(boost::move(c)), + centinel(parent.future_) { } - void launch_continuation(boost::unique_lock<boost::mutex>& ) { - run_it<shared_future_executor_continuation_shared_state> fct(this); + void launch_continuation(boost::unique_lock<boost::mutex>& lck, shared_ptr<shared_state_base> that) { + relocker relock(lck); + run_it<shared_future_executor_continuation_shared_state> fct(that); ex->submit(fct); } - static void run(shared_future_executor_continuation_shared_state* that) { + static void run(shared_ptr<boost::detail::shared_state_base> that_) { + shared_future_executor_continuation_shared_state* that = dynamic_cast<shared_future_executor_continuation_shared_state*>(that_.get()); try { that->continuation(that->parent); that->mark_finished_with_result(); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif } catch(...) { that->mark_exceptional_finish(); } } - ~shared_future_executor_continuation_shared_state() { - this->wait(false); + virtual void block_if_needed(boost::unique_lock<boost::mutex>&lk) + { + this->wait(lk, false); } + + ~shared_future_executor_continuation_shared_state() {} }; #endif ////////////////////////// @@ -4343,15 +4335,21 @@ namespace detail { F parent; Fp continuation; + shared_ptr<shared_state_base> centinel; public: future_deferred_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) : parent(boost::move(f)), - continuation(boost::move(c)) { + continuation(boost::move(c)), + centinel(parent.future_) { this->set_deferred(); } - virtual void launch_continuation(boost::unique_lock<boost::mutex>& ) { + virtual void launch_continuation(boost::unique_lock<boost::mutex>&lk, shared_ptr<shared_state_base> ) { + if (this->is_deferred_) { + this->is_deferred_=false; + this->execute(lk); + } } virtual void execute(boost::unique_lock<boost::mutex>& lck) { @@ -4373,15 +4371,23 @@ namespace detail { F parent; Fp continuation; + shared_ptr<shared_state_base> centinel; public: future_deferred_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) : parent(boost::move(f)), - continuation(boost::move(c)) { + continuation(boost::move(c)), + centinel(parent.future_) { this->set_deferred(); } - virtual void launch_continuation(boost::unique_lock<boost::mutex>& ) { + ~future_deferred_continuation_shared_state() { + } + virtual void launch_continuation(boost::unique_lock<boost::mutex>& lk, shared_ptr<shared_state_base> ) { + if (this->is_deferred_) { + this->is_deferred_=false; + this->execute(lk); + } } virtual void execute(boost::unique_lock<boost::mutex>& lck) { @@ -4406,15 +4412,21 @@ namespace detail { F parent; Fp continuation; + shared_ptr<shared_state_base> centinel; public: shared_future_deferred_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) : parent(f), - continuation(boost::move(c)) { + continuation(boost::move(c)), + centinel(parent.future_) { this->set_deferred(); } - virtual void launch_continuation(boost::unique_lock<boost::mutex>& ) { + virtual void launch_continuation(boost::unique_lock<boost::mutex>& lk, shared_ptr<shared_state_base> ) { + if (this->is_deferred_) { + this->is_deferred_=false; + this->execute(lk); + } } virtual void execute(boost::unique_lock<boost::mutex>& lck) { @@ -4436,15 +4448,21 @@ namespace detail { F parent; Fp continuation; + shared_ptr<shared_state_base> centinel; public: shared_future_deferred_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) : parent(f), - continuation(boost::move(c)) { + continuation(boost::move(c)), + centinel(parent.future_) { this->set_deferred(); } - virtual void launch_continuation(boost::unique_lock<boost::mutex>& ) { + virtual void launch_continuation(boost::unique_lock<boost::mutex>& lk, shared_ptr<shared_state_base> ) { + if (this->is_deferred_) { + this->is_deferred_=false; + this->execute(lk); + } } virtual void execute(boost::unique_lock<boost::mutex>& lck) { @@ -4471,7 +4489,9 @@ namespace detail BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) { shared_ptr<future_deferred_continuation_shared_state<F, Rp, Fp> > h(new future_deferred_continuation_shared_state<F, Rp, Fp>(boost::move(f), boost::forward<Fp>(c))); + lock.lock(); h->parent.future_->set_continuation_ptr(h, lock); + lock.unlock(); return BOOST_THREAD_FUTURE<Rp>(h); } @@ -4485,7 +4505,9 @@ namespace detail BOOST_THREAD_FWD_REF(Fp) c) { shared_ptr<future_async_continuation_shared_state<F,Rp, Fp> > h(new future_async_continuation_shared_state<F,Rp, Fp>(boost::move(f), boost::forward<Fp>(c))); + lock.lock(); h->parent.future_->set_continuation_ptr(h, lock); + lock.unlock(); return BOOST_THREAD_FUTURE<Rp>(h); } @@ -4502,7 +4524,9 @@ namespace detail BOOST_THREAD_FWD_REF(Fp) c) { shared_ptr<future_executor_continuation_shared_state<Ex,F,Rp, Fp> > h(new future_executor_continuation_shared_state<Ex, F,Rp, Fp>(ex, boost::move(f), boost::forward<Fp>(c))); + lock.lock(); h->parent.future_->set_continuation_ptr(h, lock); + lock.unlock(); return BOOST_THREAD_FUTURE<Rp>(h); } @@ -4518,7 +4542,10 @@ namespace detail F f, BOOST_THREAD_FWD_REF(Fp) c) { shared_ptr<shared_future_deferred_continuation_shared_state<F, Rp, Fp> > h(new shared_future_deferred_continuation_shared_state<F, Rp, Fp>(f, boost::forward<Fp>(c))); + lock.lock(); h->parent.future_->set_continuation_ptr(h, lock); + lock.unlock(); + return BOOST_THREAD_FUTURE<Rp>(h); } //////////////////////////////// @@ -4531,7 +4558,9 @@ namespace detail BOOST_THREAD_FWD_REF(Fp) c) { shared_ptr<shared_future_async_continuation_shared_state<F,Rp, Fp> > h(new shared_future_async_continuation_shared_state<F,Rp, Fp>(f, boost::forward<Fp>(c))); + lock.lock(); h->parent.future_->set_continuation_ptr(h, lock); + lock.unlock(); return BOOST_THREAD_FUTURE<Rp>(h); } @@ -4546,7 +4575,9 @@ namespace detail BOOST_THREAD_FWD_REF(Fp) c) { shared_ptr<shared_future_executor_continuation_shared_state<Ex, F, Rp, Fp> > h(new shared_future_executor_continuation_shared_state<Ex, F, Rp, Fp>(ex, f, boost::forward<Fp>(c))); + lock.lock(); h->parent.future_->set_continuation_ptr(h, lock); + lock.unlock(); return BOOST_THREAD_FUTURE<Rp>(h); } @@ -4567,14 +4598,18 @@ namespace detail boost::unique_lock<boost::mutex> lock(this->future_->mutex); if (underlying_cast<int>(policy) & int(launch::async)) { + lock.unlock(); return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( lock, boost::move(*this), boost::forward<F>(func) ))); } else if (underlying_cast<int>(policy) & int(launch::deferred)) { + this->future_->wait_internal(lock); + lock.unlock(); return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( lock, boost::move(*this), boost::forward<F>(func) ))); } else { + lock.unlock(); return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( lock, boost::move(*this), boost::forward<F>(func) ))); @@ -4589,6 +4624,7 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock<boost::mutex> lock(this->future_->mutex); + lock.unlock(); return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state<Ex, BOOST_THREAD_FUTURE<R>, future_type, F>(ex, lock, boost::move(*this), boost::forward<F>(func) ))); @@ -4603,6 +4639,77 @@ namespace detail boost::unique_lock<boost::mutex> lock(this->future_->mutex); if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::async)) { + lock.unlock(); + return boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( + lock, boost::move(*this), boost::forward<F>(func) + ); + } else if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::deferred)) { + this->future_->wait_internal(lock); + lock.unlock(); + return boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( + lock, boost::move(*this), boost::forward<F>(func) + ); + } else { + lock.unlock(); + return boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( + lock, boost::move(*this), boost::forward<F>(func) + ); + } + } + + //////////////////////////////// + // template<typename F> + // auto future<future<R2>>::then(F&& func) -> BOOST_THREAD_FUTURE<decltype(func(*this))>; + //////////////////////////////// + + template <typename R2> + template <typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> >)>::type> + BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> >::then(launch policy, BOOST_THREAD_FWD_REF(F) func) { + typedef BOOST_THREAD_FUTURE<R2> R; + typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); + + boost::unique_lock<boost::mutex> lock(this->future_->mutex); + if (underlying_cast<int>(policy) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( + lock, boost::move(*this), boost::forward<F>(func) + ))); + } else if (underlying_cast<int>(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( + lock, boost::move(*this), boost::forward<F>(func) + ))); + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( + lock, boost::move(*this), boost::forward<F>(func) + ))); + } + } +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template <typename R2> + template <typename Ex, typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> >)>::type> + BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> >::then(Ex& ex, BOOST_THREAD_FWD_REF(F) func) { + typedef BOOST_THREAD_FUTURE<R2> R; + typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); + + boost::unique_lock<boost::mutex> lock(this->future_->mutex); + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state<Ex, BOOST_THREAD_FUTURE<R>, future_type, F>(ex, + lock, boost::move(*this), boost::forward<F>(func) + ))); + } +#endif + template <typename R2> + template <typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> >)>::type> + BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> >::then(BOOST_THREAD_FWD_REF(F) func) { + typedef BOOST_THREAD_FUTURE<R2> R; + typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); + + boost::unique_lock<boost::mutex> lock(this->future_->mutex); + if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::async)) { return boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( lock, boost::move(*this), boost::forward<F>(func) ); @@ -4618,6 +4725,11 @@ namespace detail } } + //////////////////////////////// + // template<typename F> + // auto shared_future<R>::then(F&& func) -> BOOST_THREAD_FUTURE<decltype(func(*this))>; + //////////////////////////////// + template <typename R> template <typename F> inline BOOST_THREAD_FUTURE<typename boost::result_of<F(shared_future<R>)>::type> @@ -4627,16 +4739,19 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock<boost::mutex> lock(this->future_->mutex); - if (underlying_cast<int>(policy) & int(launch::async)) { + lock.unlock(); return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_async_continuation_shared_state<shared_future<R>, future_type, F>( lock, *this, boost::forward<F>(func) ))); } else if (underlying_cast<int>(policy) & int(launch::deferred)) { + this->future_->wait_internal(lock); + lock.unlock(); return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_deferred_continuation_shared_state<shared_future<R>, future_type, F>( lock, *this, boost::forward<F>(func) ))); } else { + lock.unlock(); return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_async_continuation_shared_state<shared_future<R>, future_type, F>( lock, *this, boost::forward<F>(func) ))); @@ -4652,6 +4767,7 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock<boost::mutex> lock(this->future_->mutex); + lock.unlock(); return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_executor_continuation_shared_state<Ex, shared_future<R>, future_type, F>(ex, lock, *this, boost::forward<F>(func) ))); @@ -4668,13 +4784,16 @@ namespace detail boost::unique_lock<boost::mutex> lock(this->future_->mutex); if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::async)) { + lock.unlock(); return boost::detail::make_shared_future_async_continuation_shared_state<shared_future<R>, future_type, F>( lock, *this, boost::forward<F>(func)); } else if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::deferred)) { this->future_->wait_internal(lock); + lock.unlock(); return boost::detail::make_shared_future_deferred_continuation_shared_state<shared_future<R>, future_type, F>( lock, *this, boost::forward<F>(func)); } else { + lock.unlock(); return boost::detail::make_shared_future_async_continuation_shared_state<shared_future<R>, future_type, F>( lock, *this, boost::forward<F>(func)); } @@ -4704,7 +4823,7 @@ namespace detail : value_(v) {} - T operator()(BOOST_THREAD_FUTURE<T> fut) { + T operator()(BOOST_THREAD_FUTURE<T> fut) const { return fut.get_or(value_); } @@ -4751,14 +4870,21 @@ namespace detail return boost::move(r); } - virtual void wait(bool ) { // todo see if rethrow must be used - boost::unique_lock<boost::mutex> lk(this->mutex); + virtual void wait(boost::unique_lock<boost::mutex>& lk, bool ) { // todo see if rethrow must be used parent_value(lk).wait(); } - virtual Rp get() { - boost::unique_lock<boost::mutex> lk(this->mutex); + virtual Rp get(boost::unique_lock<boost::mutex>& lk) { return parent_value(lk).get(); } +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + typedef shared_ptr<shared_state_base> continuation_ptr_type; + + virtual void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock<boost::mutex>& lock) + { + boost::unique_lock<boost::mutex> lk(parent.future_->mutex); + parent.future_->set_continuation_ptr(continuation, lk); + } +#endif }; template <class F, class Rp> @@ -4766,7 +4892,9 @@ namespace detail make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f) { shared_ptr<future_unwrap_shared_state<F, Rp> > h(new future_unwrap_shared_state<F, Rp>(boost::move(f))); + lock.lock(); h->parent.future_->set_continuation_ptr(h, lock); + lock.unlock(); return BOOST_THREAD_FUTURE<Rp>(h); } } @@ -4781,6 +4909,7 @@ namespace detail { BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock<boost::mutex> lock(this->future_->mutex); + lock.unlock(); return boost::detail::make_future_unwrap_shared_state<BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> >, R2>(lock, boost::move(*this)); } #endif @@ -4807,14 +4936,11 @@ namespace detail typedef typename F::value_type value_type; vector_type vec_; - static void run(future_when_all_vector_shared_state* that) { + static void run(shared_ptr<boost::detail::shared_state_base> that_) { + future_when_all_vector_shared_state* that = dynamic_cast<future_when_all_vector_shared_state*>(that_.get()); try { boost::wait_for_all(that->vec_.begin(), that->vec_.end()); that->mark_finished_with_result(boost::move(that->vec_)); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif } catch(...) { that->mark_exceptional_finish(); } @@ -4833,10 +4959,10 @@ namespace detail void init() { if (! run_deferred()) { - future_when_all_vector_shared_state::run(this); + future_when_all_vector_shared_state::run(this->shared_from_this()); return; } - this->thr_ = thread(&future_when_all_vector_shared_state::run, this); + this->thr_ = thread(&future_when_all_vector_shared_state::run, this->shared_from_this()); } public: @@ -4844,13 +4970,11 @@ namespace detail future_when_all_vector_shared_state(input_iterator_tag, InputIterator first, InputIterator last) : vec_(std::make_move_iterator(first), std::make_move_iterator(last)) { - init(); } future_when_all_vector_shared_state(vector_tag, BOOST_THREAD_RV_REF(csbl::vector<F>) v) : vec_(boost::move(v)) { - init(); } #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -4862,12 +4986,10 @@ namespace detail vec_.push_back(boost::forward<T>(futures)),'0' )..., '0' }; //second part of magic unpacker - init(); } #endif - ~future_when_all_vector_shared_state() { - this->join(); - } + + ~future_when_all_vector_shared_state() {} }; //////////////////////////////// @@ -4880,15 +5002,12 @@ namespace detail typedef typename F::value_type value_type; vector_type vec_; - static void run(future_when_any_vector_shared_state* that) + static void run(shared_ptr<boost::detail::shared_state_base> that_) { + future_when_any_vector_shared_state* that = dynamic_cast<future_when_any_vector_shared_state*>(that_.get()); try { boost::wait_for_any(that->vec_.begin(), that->vec_.end()); that->mark_finished_with_result(boost::move(that->vec_)); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif } catch(...) { that->mark_exceptional_finish(); } @@ -4906,11 +5025,11 @@ namespace detail void init() { if (run_deferred()) { - future_when_any_vector_shared_state::run(this); + future_when_any_vector_shared_state::run(this->shared_from_this()); return; } - this->thr_ = thread(&future_when_any_vector_shared_state::run, this); + this->thr_ = thread(&future_when_any_vector_shared_state::run, this->shared_from_this()); } public: @@ -4918,13 +5037,11 @@ namespace detail future_when_any_vector_shared_state(input_iterator_tag, InputIterator first, InputIterator last) : vec_(std::make_move_iterator(first), std::make_move_iterator(last)) { - init(); } future_when_any_vector_shared_state(vector_tag, BOOST_THREAD_RV_REF(csbl::vector<F>) v) : vec_(boost::move(v)) { - init(); } #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -4940,13 +5057,10 @@ namespace detail )..., '0' }; //second part of magic unpacker - init(); } #endif - ~future_when_any_vector_shared_state() { - this->join(); - } + ~future_when_any_vector_shared_state() {} }; #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -4987,16 +5101,13 @@ namespace detail Tuple tup_; typedef typename make_tuple_indices<1+sizeof...(T)>::type Index; - static void run(future_when_all_tuple_shared_state* that) { + static void run(shared_ptr<boost::detail::shared_state_base> that_) { + future_when_all_tuple_shared_state* that = dynamic_cast<future_when_all_tuple_shared_state*>(that_.get()); try { // TODO make use of apply(that->tup_, boost::detail::wait_for_all_fctor()); that->wait_for_all(Index()); that->mark_finished_with_result(boost::move(that->tup_)); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif } catch(...) { that->mark_exceptional_finish(); } @@ -5018,23 +5129,21 @@ namespace detail void init() { if (! run_deferred()) { - future_when_all_tuple_shared_state::run(this); + future_when_all_tuple_shared_state::run(this->shared_from_this()); return; } - this->thr_ = thread(&future_when_all_tuple_shared_state::run, this); + this->thr_ = thread(&future_when_all_tuple_shared_state::run, this->shared_from_this()); } public: template< typename F, typename ...Fs> future_when_all_tuple_shared_state(values_tag, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Fs) ... futures) : tup_(boost::csbl::make_tuple(boost::forward<F>(f), boost::forward<Fs>(futures)...)) { - init(); - } - ~future_when_all_tuple_shared_state() { - this->join(); } + ~future_when_all_tuple_shared_state() {} + }; @@ -5060,17 +5169,14 @@ namespace detail Tuple tup_; typedef typename make_tuple_indices<1+sizeof...(T)>::type Index; - static void run(future_when_any_tuple_shared_state* that) + static void run(shared_ptr<boost::detail::shared_state_base> that_) { + future_when_any_tuple_shared_state* that = dynamic_cast<future_when_any_tuple_shared_state*>(that_.get()); try { // TODO make use of apply(that->tup_, wait_for_any_fctr); that->wait_for_any(Index()); that->mark_finished_with_result(boost::move(that->tup_)); -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - } catch(thread_interrupted& ) { - that->mark_interrupted_finish(); -#endif } catch(...) { that->mark_exceptional_finish(); } @@ -5089,11 +5195,11 @@ namespace detail void init() { if (run_deferred()) { - future_when_any_tuple_shared_state::run(this); + future_when_any_tuple_shared_state::run(this->shared_from_this()); return; } - this->thr_ = thread(&future_when_any_tuple_shared_state::run, this); + this->thr_ = thread(&future_when_any_tuple_shared_state::run, this->shared_from_this()); } public: @@ -5103,12 +5209,9 @@ namespace detail ) : tup_(boost::csbl::make_tuple(boost::forward<F>(f), boost::forward<Fs>(futures)...)) { - init(); } - ~future_when_any_tuple_shared_state() { - this->join(); - } + ~future_when_any_tuple_shared_state() {} }; #endif @@ -5126,6 +5229,7 @@ namespace detail if (first==last) return make_ready_future(container_type()); shared_ptr<factory_type > h(new factory_type(detail::input_iterator_tag_value, first,last)); + h->init(); return BOOST_THREAD_FUTURE<container_type>(h); } @@ -5142,6 +5246,7 @@ namespace detail shared_ptr<factory_type> h(new factory_type(detail::values_tag_value, boost::forward<T0>(f), boost::forward<T>(futures)...)); + h->init(); return BOOST_THREAD_FUTURE<container_type>(h); } #endif @@ -5158,6 +5263,7 @@ namespace detail if (first==last) return make_ready_future(container_type()); shared_ptr<factory_type > h(new factory_type(detail::input_iterator_tag_value, first,last)); + h->init(); return BOOST_THREAD_FUTURE<container_type>(h); } @@ -5174,6 +5280,7 @@ namespace detail shared_ptr<factory_type> h(new factory_type(detail::values_tag_value, boost::forward<T0>(f), boost::forward<T>(futures)...)); + h->init(); return BOOST_THREAD_FUTURE<container_type>(h); } #endif diff --git a/boost/thread/futures/future_error.hpp b/boost/thread/futures/future_error.hpp new file mode 100644 index 0000000000..6212deece3 --- /dev/null +++ b/boost/thread/futures/future_error.hpp @@ -0,0 +1,98 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 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) + +#ifndef BOOST_THREAD_FUTURES_FUTURE_ERROR_HPP +#define BOOST_THREAD_FUTURES_FUTURE_ERROR_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/thread/futures/future_error_code.hpp> +#include <boost/system/error_code.hpp> + +#include <stdexcept> + +namespace boost +{ + class BOOST_SYMBOL_VISIBLE future_error + : public std::logic_error + { + system::error_code ec_; + public: + future_error(system::error_code ec) + : logic_error(ec.message()), + ec_(ec) + { + } + + const system::error_code& code() const BOOST_NOEXCEPT + { + return ec_; + } + }; + + class BOOST_SYMBOL_VISIBLE future_uninitialized: + public future_error + { + public: + future_uninitialized() : + future_error(system::make_error_code(future_errc::no_state)) + {} + }; + class BOOST_SYMBOL_VISIBLE broken_promise: + public future_error + { + public: + broken_promise(): + future_error(system::make_error_code(future_errc::broken_promise)) + {} + }; + class BOOST_SYMBOL_VISIBLE future_already_retrieved: + public future_error + { + public: + future_already_retrieved(): + future_error(system::make_error_code(future_errc::future_already_retrieved)) + {} + }; + class BOOST_SYMBOL_VISIBLE promise_already_satisfied: + public future_error + { + public: + promise_already_satisfied(): + future_error(system::make_error_code(future_errc::promise_already_satisfied)) + {} + }; + + class BOOST_SYMBOL_VISIBLE task_already_started: + public future_error + { + public: + task_already_started(): + future_error(system::make_error_code(future_errc::promise_already_satisfied)) + {} + }; + + class BOOST_SYMBOL_VISIBLE task_moved: + public future_error + { + public: + task_moved(): + future_error(system::make_error_code(future_errc::no_state)) + {} + }; + + class promise_moved: + public future_error + { + public: + promise_moved(): + future_error(system::make_error_code(future_errc::no_state)) + {} + }; +} + +#endif // header diff --git a/boost/thread/future_error_code.hpp b/boost/thread/futures/future_error_code.hpp index 6fe95541b7..7c8b6f2696 100644 --- a/boost/thread/future_error_code.hpp +++ b/boost/thread/futures/future_error_code.hpp @@ -1,12 +1,12 @@ // (C) Copyright 2008-10 Anthony Williams -// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// (C) Copyright 2011-2012,2015 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) -#ifndef BOOST_THREAD_FUTURE_ERROR_CODE_HPP -#define BOOST_THREAD_FUTURE_ERROR_CODE_HPP +#ifndef BOOST_THREAD_FUTURES_FUTURE_ERROR_CODE_HPP +#define BOOST_THREAD_FUTURES_FUTURE_ERROR_CODE_HPP #include <boost/thread/detail/config.hpp> #include <boost/core/scoped_enum.hpp> diff --git a/boost/thread/futures/future_status.hpp b/boost/thread/futures/future_status.hpp new file mode 100644 index 0000000000..383ac4673c --- /dev/null +++ b/boost/thread/futures/future_status.hpp @@ -0,0 +1,30 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 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) + +#ifndef BOOST_THREAD_FUTURES_FUTURE_STATUS_HPP +#define BOOST_THREAD_FUTURES_FUTURE_STATUS_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/core/scoped_enum.hpp> + +namespace boost +{ + //enum class future_status + BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_status) + { + ready, + timeout, + deferred + } + BOOST_SCOPED_ENUM_DECLARE_END(future_status) + namespace future_state + { + enum state { uninitialized, waiting, ready, moved, deferred }; + } +} + +#endif // header diff --git a/boost/thread/futures/is_future_type.hpp b/boost/thread/futures/is_future_type.hpp new file mode 100644 index 0000000000..df7a680faa --- /dev/null +++ b/boost/thread/futures/is_future_type.hpp @@ -0,0 +1,21 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 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) + +#ifndef BOOST_THREAD_FUTURES_IS_FUTURE_TYPE_HPP +#define BOOST_THREAD_FUTURES_IS_FUTURE_TYPE_HPP + +#include <boost/type_traits/integral_constant.hpp> + +namespace boost +{ + template<typename T> + struct is_future_type : false_type + { + }; +} + +#endif // header diff --git a/boost/thread/futures/launch.hpp b/boost/thread/futures/launch.hpp new file mode 100644 index 0000000000..b457020aaa --- /dev/null +++ b/boost/thread/futures/launch.hpp @@ -0,0 +1,30 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 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) + +#ifndef BOOST_THREAD_FUTURES_LAUNCH_HPP +#define BOOST_THREAD_FUTURES_LAUNCH_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/core/scoped_enum.hpp> + +namespace boost +{ + //enum class launch + BOOST_SCOPED_ENUM_DECLARE_BEGIN(launch) + { + none = 0, + async = 1, + deferred = 2, +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + executor = 4, +#endif + any = async | deferred + } + BOOST_SCOPED_ENUM_DECLARE_END(launch) +} + +#endif // header diff --git a/boost/thread/futures/wait_for_all.hpp b/boost/thread/futures/wait_for_all.hpp new file mode 100644 index 0000000000..90cc2b77cb --- /dev/null +++ b/boost/thread/futures/wait_for_all.hpp @@ -0,0 +1,74 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 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) + +#ifndef BOOST_THREAD_FUTURES_WAIT_FOR_ALL_HPP +#define BOOST_THREAD_FUTURES_WAIT_FOR_ALL_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/futures/is_future_type.hpp> + +#include <boost/core/enable_if.hpp> + +namespace boost +{ + template<typename Iterator> + typename boost::disable_if<is_future_type<Iterator>,void>::type wait_for_all(Iterator begin,Iterator end) + { + for(Iterator current=begin;current!=end;++current) + { + current->wait(); + } + } + +#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template<typename F1,typename F2> + typename boost::enable_if<is_future_type<F1>,void>::type wait_for_all(F1& f1,F2& f2) + { + f1.wait(); + f2.wait(); + } + + template<typename F1,typename F2,typename F3> + void wait_for_all(F1& f1,F2& f2,F3& f3) + { + f1.wait(); + f2.wait(); + f3.wait(); + } + + template<typename F1,typename F2,typename F3,typename F4> + void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4) + { + f1.wait(); + f2.wait(); + f3.wait(); + f4.wait(); + } + + template<typename F1,typename F2,typename F3,typename F4,typename F5> + void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5) + { + f1.wait(); + f2.wait(); + f3.wait(); + f4.wait(); + f5.wait(); + } +#else + template<typename F1, typename... Fs> + void wait_for_all(F1& f1, Fs&... fs) + { + bool dummy[] = { (f1.wait(), true), (fs.wait(), true)... }; + + // prevent unused parameter warning + (void) dummy; + } +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)} + +} + +#endif // header diff --git a/boost/thread/futures/wait_for_any.hpp b/boost/thread/futures/wait_for_any.hpp new file mode 100644 index 0000000000..b869a4318a --- /dev/null +++ b/boost/thread/futures/wait_for_any.hpp @@ -0,0 +1,161 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 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) + +#ifndef BOOST_THREAD_FUTURES_WAIT_FOR_ANY_HPP +#define BOOST_THREAD_FUTURES_WAIT_FOR_ANY_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/thread/detail/move.hpp> +#include <boost/thread/futures/is_future_type.hpp> +#include <boost/thread/lock_algorithms.hpp> +#include <boost/thread/mutex.hpp> + +#include <boost/core/enable_if.hpp> +#include <boost/next_prior.hpp> +#include <boost/scoped_array.hpp> + +#include <iterator> +#include <vector> + +namespace boost +{ + namespace detail + { + template <class Future> + class waiter_for_any_in_seq + { + struct registered_waiter; + typedef std::vector<int>::size_type count_type; + + struct registered_waiter + { + typedef Future future_type; + future_type* future_; + typedef typename Future::notify_when_ready_handle notify_when_ready_handle; + notify_when_ready_handle handle; + count_type index; + + registered_waiter(future_type & a_future, + notify_when_ready_handle handle_, count_type index_) : + future_(&a_future), handle(handle_), index(index_) + { + } + }; + + struct all_futures_lock + { +#ifdef _MANAGED + typedef std::ptrdiff_t count_type_portable; +#else + typedef count_type count_type_portable; +#endif + count_type_portable count; + boost::scoped_array<boost::unique_lock<boost::mutex> > locks; + + all_futures_lock(std::vector<registered_waiter>& waiters) : + count(waiters.size()), locks(new boost::unique_lock<boost::mutex>[count]) + { + for (count_type_portable i = 0; i < count; ++i) + { + locks[i] = BOOST_THREAD_MAKE_RV_REF(boost::unique_lock<boost::mutex>(waiters[i].future_->mutex())); + } + } + + void lock() + { + boost::lock(locks.get(), locks.get() + count); + } + + void unlock() + { + for (count_type_portable i = 0; i < count; ++i) + { + locks[i].unlock(); + } + } + }; + + boost::condition_variable_any cv; + std::vector<registered_waiter> waiters_; + count_type future_count; + + public: + waiter_for_any_in_seq() : + future_count(0) + { + } + + template <typename F> + void add(F& f) + { + if (f.valid()) + { + registered_waiter waiter(f, f.notify_when_ready(cv), future_count); + try + { + waiters_.push_back(waiter); + } + catch (...) + { + f.future_->unnotify_when_ready(waiter.handle); + throw; + } + ++future_count; + } + } + +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template <typename F1, typename ... Fs> + void add(F1& f1, Fs&... fs) + { + add(f1); + add(fs...); + } +#endif + + count_type wait() + { + all_futures_lock lk(waiters_); + for (;;) + { + for (count_type i = 0; i < waiters_.size(); ++i) + { + if (waiters_[i].future_->is_ready(lk.locks[i])) + { + return waiters_[i].index; + } + } + cv.wait(lk); + } + } + + ~waiter_for_any_in_seq() + { + for (count_type i = 0; i < waiters_.size(); ++i) + { + waiters_[i].future_->unnotify_when_ready(waiters_[i].handle); + } + } + }; + } + + template <typename Iterator> + typename boost::disable_if<is_future_type<Iterator> , Iterator>::type wait_for_any(Iterator begin, Iterator end) + { + if (begin == end) return end; + + detail::waiter_for_any_in_seq<typename std::iterator_traits<Iterator>::value_type> waiter; + for (Iterator current = begin; current != end; ++current) + { + waiter.add(*current); + } + return boost::next(begin, waiter.wait()); + } +} + +#endif // header diff --git a/boost/thread/latch.hpp b/boost/thread/latch.hpp index 6caf521910..8fa9d963de 100644 --- a/boost/thread/latch.hpp +++ b/boost/thread/latch.hpp @@ -27,7 +27,7 @@ namespace boost /// Effect: Decrement the count. Unlocks the lock and notify anyone waiting if we reached zero. /// Returns: true if count_ reached the value 0. /// @ThreadSafe ensured by the @c lk parameter - bool count_down(unique_lock<mutex> &lk) + bool count_down(unique_lock<mutex> &) /// pre_condition (count_ > 0) { BOOST_ASSERT(count_ > 0); diff --git a/boost/thread/pthread/mutex.hpp b/boost/thread/pthread/mutex.hpp index 3e9af2a833..9ac808b6f4 100644 --- a/boost/thread/pthread/mutex.hpp +++ b/boost/thread/pthread/mutex.hpp @@ -1,12 +1,13 @@ #ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP #define BOOST_THREAD_PTHREAD_MUTEX_HPP // (C) Copyright 2007-8 Anthony Williams -// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// (C) Copyright 2011,2012,2015 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) #include <boost/thread/detail/config.hpp> +#include <boost/assert.hpp> #include <pthread.h> #include <boost/throw_exception.hpp> #include <boost/core/ignore_unused.hpp> @@ -26,13 +27,12 @@ #endif #include <boost/thread/detail/delete.hpp> -#ifdef _POSIX_TIMEOUTS -#if _POSIX_TIMEOUTS >= 0 && _POSIX_TIMEOUTS>=200112L +#if (defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS-0)>=200112L) \ + || (defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21) #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK #define BOOST_PTHREAD_HAS_TIMEDLOCK #endif #endif -#endif #include <boost/config/abi_prefix.hpp> @@ -123,10 +123,12 @@ namespace boost void unlock() { int res = posix::pthread_mutex_unlock(&m); - if (res) - { - boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); - } + (void)res; + BOOST_ASSERT(res == 0); +// if (res) +// { +// boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); +// } } bool try_lock() @@ -219,10 +221,12 @@ namespace boost void unlock() { int res = posix::pthread_mutex_unlock(&m); - if (res) - { - boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); - } + (void)res; + BOOST_ASSERT(res == 0); +// if (res) +// { +// boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); +// } } bool try_lock() diff --git a/boost/thread/pthread/recursive_mutex.hpp b/boost/thread/pthread/recursive_mutex.hpp index 9330d77de9..4caae0b5df 100644 --- a/boost/thread/pthread/recursive_mutex.hpp +++ b/boost/thread/pthread/recursive_mutex.hpp @@ -27,16 +27,19 @@ #endif #include <boost/thread/detail/delete.hpp> -#ifdef _POSIX_TIMEOUTS -#if _POSIX_TIMEOUTS >= 0 && _POSIX_TIMEOUTS>=200112L +#if (defined _POSIX_TIMEOUTS && (_POSIX_TIMEOUTS-0)>=200112L) \ + || (defined __ANDROID__ && defined __ANDROID_API__ && __ANDROID_API__ >= 21) #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK #define BOOST_PTHREAD_HAS_TIMEDLOCK #endif #endif -#endif +#if defined BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE \ + || defined __ANDROID__ +#define BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE +#endif -#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) && defined(BOOST_PTHREAD_HAS_TIMEDLOCK) +#if defined BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE && defined BOOST_PTHREAD_HAS_TIMEDLOCK #define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK #endif @@ -48,7 +51,7 @@ namespace boost { private: pthread_mutex_t m; -#ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +#ifndef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE pthread_cond_t cond; bool is_locked; pthread_t owner; @@ -58,7 +61,7 @@ namespace boost BOOST_THREAD_NO_COPYABLE(recursive_mutex) recursive_mutex() { -#ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +#ifdef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE pthread_mutexattr_t attr; int const init_attr_res=pthread_mutexattr_init(&attr); @@ -99,12 +102,12 @@ namespace boost ~recursive_mutex() { BOOST_VERIFY(!pthread_mutex_destroy(&m)); -#ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +#ifndef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE BOOST_VERIFY(!pthread_cond_destroy(&cond)); #endif } -#ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +#ifdef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE void lock() { BOOST_VERIFY(!pthread_mutex_lock(&m)); diff --git a/boost/thread/pthread/thread_data.hpp b/boost/thread/pthread/thread_data.hpp index 801f470b46..dc8ba0fb1b 100644 --- a/boost/thread/pthread/thread_data.hpp +++ b/boost/thread/pthread/thread_data.hpp @@ -25,7 +25,9 @@ #include <utility> #if defined(__ANDROID__) -#include <asm/page.h> // http://code.google.com/p/android/issues/detail?id=39983 +# ifndef PAGE_SIZE +# define PAGE_SIZE 4096 +# endif #endif #include <pthread.h> @@ -113,8 +115,13 @@ namespace boost boost::detail::thread_exit_callback_node* thread_exit_callbacks; std::map<void const*,boost::detail::tss_data_node> tss_data; +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + // These data must be at the end so that the access to the other fields doesn't change + // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined. + // Another option is to have them always pthread_mutex_t* cond_mutex; pthread_cond_t* current_cond; +//#endif typedef std::vector<std::pair<condition_variable*, mutex*> //, hidden_allocator<std::pair<condition_variable*, mutex*> > > notify_list_t; @@ -134,8 +141,10 @@ namespace boost thread_handle(0), done(false),join_started(false),joined(false), thread_exit_callbacks(0), +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS cond_mutex(0), current_cond(0), +//#endif notify(), async_states_() //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS @@ -250,7 +259,7 @@ namespace boost inline void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) { - return boost::this_thread::hiden::sleep_for(boost::detail::to_timespec(ns)); + return boost::this_thread::no_interruption_point::hiden::sleep_for(boost::detail::to_timespec(ns)); } #endif #endif // BOOST_THREAD_USES_CHRONO diff --git a/boost/thread/sync_bounded_queue.hpp b/boost/thread/sync_bounded_queue.hpp index 63afb614ee..2024d6602e 100644 --- a/boost/thread/sync_bounded_queue.hpp +++ b/boost/thread/sync_bounded_queue.hpp @@ -11,712 +11,6 @@ // ////////////////////////////////////////////////////////////////////////////// -#include <boost/thread/detail/config.hpp> -#include <boost/thread/condition_variable.hpp> -#include <boost/thread/mutex.hpp> -#include <boost/thread/detail/move.hpp> -#include <boost/throw_exception.hpp> -#include <boost/thread/concurrent_queues/queue_op_status.hpp> - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD -#include <boost/smart_ptr/shared_ptr.hpp> -#include <boost/smart_ptr/make_shared.hpp> -#endif -#include <boost/config/abi_prefix.hpp> - -namespace boost -{ - - template <typename ValueType> - class sync_bounded_queue - { - public: - typedef ValueType value_type; - typedef std::size_t size_type; - - // Constructors/Assignment/Destructors - BOOST_THREAD_NO_COPYABLE(sync_bounded_queue) - explicit sync_bounded_queue(size_type max_elems); - template <typename Range> - sync_bounded_queue(size_type max_elems, Range range); - ~sync_bounded_queue(); - - // Observers - inline bool empty() const; - inline bool full() const; - inline size_type capacity() const; - inline size_type size() const; - inline bool closed() const; - - // Modifiers - inline void close(); - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - inline void push(const value_type& x); - inline void push(BOOST_THREAD_RV_REF(value_type) x); - inline bool try_push(const value_type& x); - inline bool try_push(BOOST_THREAD_RV_REF(value_type) x); - inline bool try_push(no_block_tag, const value_type& x); - inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x); -#endif - inline void push_back(const value_type& x); - inline void push_back(BOOST_THREAD_RV_REF(value_type) x); - inline queue_op_status try_push_back(const value_type& x); - inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x); - inline queue_op_status nonblocking_push_back(const value_type& x); - inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x); - inline queue_op_status wait_push_back(const value_type& x); - inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x); - - // Observers/Modifiers -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - inline void pull(value_type&); - // enable_if is_nothrow_copy_movable<value_type> - inline value_type pull(); - inline shared_ptr<ValueType> ptr_pull(); - inline bool try_pull(value_type&); - inline bool try_pull(no_block_tag,value_type&); - inline shared_ptr<ValueType> try_pull(); -#endif - inline void pull_front(value_type&); - // enable_if is_nothrow_copy_movable<value_type> - inline value_type pull_front(); - inline queue_op_status try_pull_front(value_type&); - inline queue_op_status nonblocking_pull_front(value_type&); - - inline queue_op_status wait_pull_front(ValueType& elem); - - private: - mutable mutex mtx_; - condition_variable not_empty_; - condition_variable not_full_; - size_type waiting_full_; - size_type waiting_empty_; - value_type* data_; - size_type in_; - size_type out_; - size_type capacity_; - bool closed_; - - inline size_type inc(size_type idx) const BOOST_NOEXCEPT - { - return (idx + 1) % capacity_; - } - - inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT - { - return in_ == out_; - } - inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT - { - return in_ == out_; - } - inline bool full(unique_lock<mutex>& ) const BOOST_NOEXCEPT - { - return (inc(in_) == out_); - } - inline bool full(lock_guard<mutex>& ) const BOOST_NOEXCEPT - { - return (inc(in_) == out_); - } - inline size_type capacity(lock_guard<mutex>& ) const BOOST_NOEXCEPT - { - return capacity_-1; - } - inline size_type size(lock_guard<mutex>& lk) const BOOST_NOEXCEPT - { - if (full(lk)) return capacity(lk); - return ((out_+capacity(lk)-in_) % capacity(lk)); - } - - inline void throw_if_closed(unique_lock<mutex>&); - inline bool closed(unique_lock<mutex>&) const; - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - inline bool try_pull(value_type& x, unique_lock<mutex>& lk); - inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk); - inline bool try_push(const value_type& x, unique_lock<mutex>& lk); - inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); -#endif - inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk); - inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk); - inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); - - inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk); - inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk); - inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); - - inline void wait_until_not_empty(unique_lock<mutex>& lk); - inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&); - inline size_type wait_until_not_full(unique_lock<mutex>& lk); - inline size_type wait_until_not_full(unique_lock<mutex>& lk, bool&); - - - inline void notify_not_empty_if_needed(unique_lock<mutex>& lk) - { - if (waiting_empty_ > 0) - { - --waiting_empty_; - lk.unlock(); - not_empty_.notify_one(); - } - } - inline void notify_not_full_if_needed(unique_lock<mutex>& lk) - { - if (waiting_full_ > 0) - { - --waiting_full_; - lk.unlock(); - not_full_.notify_one(); - } - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - inline void pull(value_type& elem, unique_lock<mutex>& lk) - { - elem = boost::move(data_[out_]); - out_ = inc(out_); - notify_not_full_if_needed(lk); - } - inline value_type pull(unique_lock<mutex>& lk) - { - value_type elem = boost::move(data_[out_]); - out_ = inc(out_); - notify_not_full_if_needed(lk); - return boost::move(elem); - } - inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk) - { - shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_[out_])); - out_ = inc(out_); - notify_not_full_if_needed(lk); - return res; - } -#endif - inline void pull_front(value_type& elem, unique_lock<mutex>& lk) - { - elem = boost::move(data_[out_]); - out_ = inc(out_); - notify_not_full_if_needed(lk); - } - inline value_type pull_front(unique_lock<mutex>& lk) - { - value_type elem = boost::move(data_[out_]); - out_ = inc(out_); - notify_not_full_if_needed(lk); - return boost::move(elem); - } - - inline void set_in(size_type in, unique_lock<mutex>& lk) - { - in_ = in; - notify_not_empty_if_needed(lk); - } - - inline void push_at(const value_type& elem, size_type in_p_1, unique_lock<mutex>& lk) - { - data_[in_] = elem; - set_in(in_p_1, lk); - } - - inline void push_at(BOOST_THREAD_RV_REF(value_type) elem, size_type in_p_1, unique_lock<mutex>& lk) - { - data_[in_] = boost::move(elem); - set_in(in_p_1, lk); - } - }; - - template <typename ValueType> - sync_bounded_queue<ValueType>::sync_bounded_queue(typename sync_bounded_queue<ValueType>::size_type max_elems) : - waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1), - closed_(false) - { - BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1"); - } - -// template <typename ValueType> -// template <typename Range> -// sync_bounded_queue<ValueType>::sync_bounded_queue(size_type max_elems, Range range) : -// waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1), -// closed_(false) -// { -// BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1"); -// BOOST_ASSERT_MSG(max_elems == size(range), "number of elements must match range's size"); -// try -// { -// typedef typename Range::iterator iterator_t; -// iterator_t first = boost::begin(range); -// iterator_t end = boost::end(range); -// size_type in = 0; -// for (iterator_t cur = first; cur != end; ++cur, ++in) -// { -// data_[in] = *cur; -// } -// set_in(in); -// } -// catch (...) -// { -// delete[] data_; -// } -// } - - template <typename ValueType> - sync_bounded_queue<ValueType>::~sync_bounded_queue() - { - delete[] data_; - } - - template <typename ValueType> - void sync_bounded_queue<ValueType>::close() - { - { - lock_guard<mutex> lk(mtx_); - closed_ = true; - } - not_empty_.notify_all(); - not_full_.notify_all(); - } - - template <typename ValueType> - bool sync_bounded_queue<ValueType>::closed() const - { - lock_guard<mutex> lk(mtx_); - return closed_; - } - template <typename ValueType> - bool sync_bounded_queue<ValueType>::closed(unique_lock<mutex>& ) const - { - return closed_; - } - - template <typename ValueType> - bool sync_bounded_queue<ValueType>::empty() const - { - lock_guard<mutex> lk(mtx_); - return empty(lk); - } - template <typename ValueType> - bool sync_bounded_queue<ValueType>::full() const - { - lock_guard<mutex> lk(mtx_); - return full(lk); - } - - template <typename ValueType> - typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::capacity() const - { - lock_guard<mutex> lk(mtx_); - return capacity(lk); - } - - template <typename ValueType> - typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::size() const - { - lock_guard<mutex> lk(mtx_); - return size(lk); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk) - { - if (empty(lk)) - { - throw_if_closed(lk); - return false; - } - pull(elem, lk); - return true; - } - template <typename ValueType> - shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull(unique_lock<mutex>& lk) - { - if (empty(lk)) - { - throw_if_closed(lk); - return shared_ptr<ValueType>(); - } - return ptr_pull(lk); - } - template <typename ValueType> - bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - return try_pull(elem, lk); - } -#endif - - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk) - { - if (empty(lk)) - { - if (closed(lk)) return queue_op_status::closed; - return queue_op_status::empty; - } - pull_front(elem, lk); - return queue_op_status::success; - } - - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - return try_pull_front(elem, lk); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_bounded_queue<ValueType>::try_pull(no_block_tag,ValueType& elem) - { - unique_lock<mutex> lk(mtx_, try_to_lock); - if (!lk.owns_lock()) - { - return false; - } - return try_pull(elem, lk); - } - template <typename ValueType> - boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull() - { - unique_lock<mutex> lk(mtx_); - return try_pull(lk); - } -#endif - - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::nonblocking_pull_front(ValueType& elem) - { - unique_lock<mutex> lk(mtx_, try_to_lock); - if (!lk.owns_lock()) - { - return queue_op_status::busy; - } - return try_pull_front(elem, lk); - } - - template <typename ValueType> - void sync_bounded_queue<ValueType>::throw_if_closed(unique_lock<mutex>&) - { - if (closed_) - { - BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); - } - } - - template <typename ValueType> - void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk) - { - for (;;) - { - if (out_ != in_) break; - throw_if_closed(lk); - ++waiting_empty_; - not_empty_.wait(lk); - } - } - template <typename ValueType> - void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed) - { - for (;;) - { - if (out_ != in_) break; - if (closed_) {closed=true; return;} - ++waiting_empty_; - not_empty_.wait(lk); - } - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - void sync_bounded_queue<ValueType>::pull(ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - wait_until_not_empty(lk); - pull(elem, lk); - } -// template <typename ValueType> -// void sync_bounded_queue<ValueType>::pull(ValueType& elem, bool & closed) -// { -// unique_lock<mutex> lk(mtx_); -// wait_until_not_empty(lk, closed); -// if (closed) {return;} -// pull(elem, lk); -// } - - // enable if ValueType is nothrow movable - template <typename ValueType> - ValueType sync_bounded_queue<ValueType>::pull() - { - unique_lock<mutex> lk(mtx_); - wait_until_not_empty(lk); - return pull(lk); - } - template <typename ValueType> - boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::ptr_pull() - { - unique_lock<mutex> lk(mtx_); - wait_until_not_empty(lk); - return ptr_pull(lk); - } - -#endif - - template <typename ValueType> - void sync_bounded_queue<ValueType>::pull_front(ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - wait_until_not_empty(lk); - pull_front(elem, lk); - } - - // enable if ValueType is nothrow movable - template <typename ValueType> - ValueType sync_bounded_queue<ValueType>::pull_front() - { - unique_lock<mutex> lk(mtx_); - wait_until_not_empty(lk); - return pull_front(lk); - } - - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk) - { - if (empty(lk) && closed(lk)) {return queue_op_status::closed;} - wait_until_not_empty(lk); - pull_front(elem, lk); - return queue_op_status::success; - } - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - return wait_pull_front(elem, lk); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk) - { - throw_if_closed(lk); - size_type in_p_1 = inc(in_); - if (in_p_1 == out_) // full() - { - return false; - } - push_at(elem, in_p_1, lk); - return true; - } - template <typename ValueType> - bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - return try_push(elem, lk); - } - -#endif - - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk) - { - if (closed(lk)) return queue_op_status::closed; - size_type in_p_1 = inc(in_); - if (in_p_1 == out_) // full() - { - return queue_op_status::full; - } - push_at(elem, in_p_1, lk); - return queue_op_status::success; - } - - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - return try_push_back(elem, lk); - } - - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk) - { - if (closed(lk)) return queue_op_status::closed; - push_at(elem, wait_until_not_full(lk), lk); - return queue_op_status::success; - } - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - return wait_push_back(elem, lk); - } - - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_bounded_queue<ValueType>::try_push(no_block_tag, const ValueType& elem) - { - unique_lock<mutex> lk(mtx_, try_to_lock); - if (!lk.owns_lock()) return false; - return try_push(elem, lk); - } -#endif - - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(const ValueType& elem) - { - unique_lock<mutex> lk(mtx_, try_to_lock); - if (!lk.owns_lock()) return queue_op_status::busy; - return try_push_back(elem, lk); - } - - template <typename ValueType> - typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::wait_until_not_full(unique_lock<mutex>& lk) - { - for (;;) - { - throw_if_closed(lk); - size_type in_p_1 = inc(in_); - if (in_p_1 != out_) // ! full() - { - return in_p_1; - } - ++waiting_full_; - not_full_.wait(lk); - } - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - void sync_bounded_queue<ValueType>::push(const ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - push_at(elem, wait_until_not_full(lk), lk); - } -#endif - template <typename ValueType> - void sync_bounded_queue<ValueType>::push_back(const ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - push_at(elem, wait_until_not_full(lk), lk); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) - { - throw_if_closed(lk); - size_type in_p_1 = inc(in_); - if (in_p_1 == out_) // full() - { - return false; - } - push_at(boost::move(elem), in_p_1, lk); - return true; - } - - template <typename ValueType> - bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_); - return try_push(boost::move(elem), lk); - } -#endif - - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) - { - if (closed(lk)) return queue_op_status::closed; - size_type in_p_1 = inc(in_); - if (in_p_1 == out_) // full() - { - return queue_op_status::full; - } - push_at(boost::move(elem), in_p_1, lk); - return queue_op_status::success; - } - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_); - return try_push_back(boost::move(elem), lk); - } - - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) - { - if (closed(lk)) return queue_op_status::closed; - push_at(boost::move(elem), wait_until_not_full(lk), lk); - return queue_op_status::success; - } - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_); - return try_push_back(boost::move(elem), lk); - } - - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_bounded_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_, try_to_lock); - if (!lk.owns_lock()) - { - return false; - } - return try_push(boost::move(elem), lk); - } -#endif - template <typename ValueType> - queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_, try_to_lock); - if (!lk.owns_lock()) - { - return queue_op_status::busy; - } - return try_push_back(boost::move(elem), lk); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - void sync_bounded_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_); - push_at(boost::move(elem), wait_until_not_full(lk), lk); - } -#endif - template <typename ValueType> - void sync_bounded_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_); - push_at(boost::move(elem), wait_until_not_full(lk), lk); - } - - template <typename ValueType> - sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem) - { - sbq.push_back(boost::move(elem)); - return sbq; - } - - template <typename ValueType> - sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem) - { - sbq.push_back(elem); - return sbq; - } - - template <typename ValueType> - sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem) - { - sbq.pull_front(elem); - return sbq; - } - -} - -#include <boost/config/abi_suffix.hpp> +#include <boost/thread/concurrent_queues/sync_bounded_queue.hpp> #endif diff --git a/boost/thread/sync_queue.hpp b/boost/thread/sync_queue.hpp index 5037e909ed..0d9334b478 100644 --- a/boost/thread/sync_queue.hpp +++ b/boost/thread/sync_queue.hpp @@ -11,653 +11,6 @@ // ////////////////////////////////////////////////////////////////////////////// -#include <boost/thread/detail/config.hpp> -#include <boost/thread/condition_variable.hpp> -#include <boost/thread/mutex.hpp> -#include <boost/thread/detail/move.hpp> -#include <boost/thread/concurrent_queues/queue_op_status.hpp> - -#include <boost/throw_exception.hpp> -#include <boost/smart_ptr/shared_ptr.hpp> -#include <boost/smart_ptr/make_shared.hpp> - -#include <boost/thread/csbl/deque.hpp> - -#include <boost/config/abi_prefix.hpp> - -namespace boost -{ - - template <typename ValueType> - class sync_queue - { - public: - typedef ValueType value_type; - typedef csbl::deque<ValueType> underlying_queue_type; - typedef std::size_t size_type; - typedef queue_op_status op_status; - - // Constructors/Assignment/Destructors - BOOST_THREAD_NO_COPYABLE(sync_queue) - inline sync_queue(); - //template <typename Range> - //inline explicit sync_queue(Range range); - inline ~sync_queue(); - - // Observers - inline bool empty() const; - inline bool full() const; - inline size_type size() const; - inline bool closed() const; - - // Modifiers - inline void close(); - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - inline void push(const value_type& x); - inline bool try_push(const value_type& x); - inline bool try_push(no_block_tag, const value_type& x); - inline void push(BOOST_THREAD_RV_REF(value_type) x); - inline bool try_push(BOOST_THREAD_RV_REF(value_type) x); - inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x); -#endif - inline void push_back(const value_type& x); - inline queue_op_status try_push_back(const value_type& x); - inline queue_op_status nonblocking_push_back(const value_type& x); - inline queue_op_status wait_push_back(const value_type& x); - inline void push_back(BOOST_THREAD_RV_REF(value_type) x); - inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x); - inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x); - inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x); - - - // Observers/Modifiers -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - inline void pull(value_type&); - inline void pull(ValueType& elem, bool & closed); - // enable_if is_nothrow_copy_movable<value_type> - inline value_type pull(); - inline shared_ptr<ValueType> ptr_pull(); -#endif - inline void pull_front(value_type&); - // enable_if is_nothrow_copy_movable<value_type> - inline value_type pull_front(); - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - inline bool try_pull(value_type&); - inline bool try_pull(no_block_tag,value_type&); - inline shared_ptr<ValueType> try_pull(); -#endif - inline queue_op_status try_pull_front(value_type&); - inline queue_op_status nonblocking_pull_front(value_type&); - inline queue_op_status wait_pull_front(ValueType& elem); - - inline underlying_queue_type underlying_queue() { - lock_guard<mutex> lk(mtx_); - waiting_empty_ = 0; - return boost::move(data_); - } - - private: - mutable mutex mtx_; - condition_variable not_empty_; - size_type waiting_empty_; - underlying_queue_type data_; - bool closed_; - - inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT - { - return data_.empty(); - } - inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT - { - return data_.empty(); - } - - inline size_type size(lock_guard<mutex>& ) const BOOST_NOEXCEPT - { - return data_.size(); - } - - inline void throw_if_closed(unique_lock<mutex>&); - inline bool closed(unique_lock<mutex>& lk) const; - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - inline bool try_pull(value_type& x, unique_lock<mutex>& lk); - inline bool try_push(const value_type& x, unique_lock<mutex>& lk); - inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); - inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk); -#endif - inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk); - inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk); - inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk); - inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk); - inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); - inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); - - inline void wait_until_not_empty(unique_lock<mutex>& lk); - inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&); - - inline void notify_not_empty_if_needed(unique_lock<mutex>& lk) - { - if (waiting_empty_ > 0) - { - --waiting_empty_; - lk.unlock(); - not_empty_.notify_one(); - } - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - inline void pull(value_type& elem, unique_lock<mutex>& ) - { - elem = boost::move(data_.front()); - data_.pop_front(); - } - inline value_type pull(unique_lock<mutex>& ) - { - value_type e = boost::move(data_.front()); - data_.pop_front(); - return boost::move(e); - } - inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& ) - { - shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_.front())); - data_.pop_front(); - return res; - } -#endif - inline void pull_front(value_type& elem, unique_lock<mutex>& ) - { - elem = boost::move(data_.front()); - data_.pop_front(); - } - inline value_type pull_front(unique_lock<mutex>& ) - { - value_type e = boost::move(data_.front()); - data_.pop_front(); - return boost::move(e); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - inline void push(const value_type& elem, unique_lock<mutex>& lk) - { - data_.push_back(elem); - notify_not_empty_if_needed(lk); - } - - inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk) - { - data_.push_back(boost::move(elem)); - notify_not_empty_if_needed(lk); - } -#endif - inline void push_back(const value_type& elem, unique_lock<mutex>& lk) - { - data_.push_back(elem); - notify_not_empty_if_needed(lk); - } - - inline void push_back(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk) - { - data_.push_back(boost::move(elem)); - notify_not_empty_if_needed(lk); - } - }; - - template <typename ValueType> - sync_queue<ValueType>::sync_queue() : - waiting_empty_(0), data_(), closed_(false) - { - BOOST_ASSERT(data_.empty()); - } - -// template <typename ValueType> -// template <typename Range> -// explicit sync_queue<ValueType>::sync_queue(Range range) : -// waiting_empty_(0), data_(), closed_(false) -// { -// try -// { -// typedef typename Range::iterator iterator_t; -// iterator_t first = boost::begin(range); -// iterator_t end = boost::end(range); -// for (iterator_t cur = first; cur != end; ++cur) -// { -// data_.push(boost::move(*cur));; -// } -// notify_not_empty_if_needed(lk); -// } -// catch (...) -// { -// delete[] data_; -// } -// } - - template <typename ValueType> - sync_queue<ValueType>::~sync_queue() - { - } - - template <typename ValueType> - void sync_queue<ValueType>::close() - { - { - lock_guard<mutex> lk(mtx_); - closed_ = true; - } - not_empty_.notify_all(); - } - - template <typename ValueType> - bool sync_queue<ValueType>::closed() const - { - lock_guard<mutex> lk(mtx_); - return closed_; - } - template <typename ValueType> - bool sync_queue<ValueType>::closed(unique_lock<mutex>&) const - { - return closed_; - } - - template <typename ValueType> - bool sync_queue<ValueType>::empty() const - { - lock_guard<mutex> lk(mtx_); - return empty(lk); - } - template <typename ValueType> - bool sync_queue<ValueType>::full() const - { - return false; - } - - template <typename ValueType> - typename sync_queue<ValueType>::size_type sync_queue<ValueType>::size() const - { - lock_guard<mutex> lk(mtx_); - return size(lk); - } - - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk) - { - if (empty(lk)) - { - throw_if_closed(lk); - return false; - } - pull(elem, lk); - return true; - } - template <typename ValueType> - shared_ptr<ValueType> sync_queue<ValueType>::try_pull(unique_lock<mutex>& lk) - { - if (empty(lk)) - { - throw_if_closed(lk); - return shared_ptr<ValueType>(); - } - return ptr_pull(lk); - } -#endif - template <typename ValueType> - queue_op_status sync_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk) - { - if (empty(lk)) - { - if (closed(lk)) return queue_op_status::closed; - return queue_op_status::empty; - } - pull_front(elem, lk); - return queue_op_status::success; - } - template <typename ValueType> - queue_op_status sync_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk) - { - if (empty(lk)) - { - if (closed(lk)) return queue_op_status::closed; - } - bool has_been_closed = false; - wait_until_not_empty(lk, has_been_closed); - if (has_been_closed) return queue_op_status::closed; - pull_front(elem, lk); - return queue_op_status::success; - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_queue<ValueType>::try_pull(ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - return try_pull(elem, lk); - } -#endif - template <typename ValueType> - queue_op_status sync_queue<ValueType>::try_pull_front(ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - return try_pull_front(elem, lk); - } - - template <typename ValueType> - queue_op_status sync_queue<ValueType>::wait_pull_front(ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - return wait_pull_front(elem, lk); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_queue<ValueType>::try_pull(no_block_tag,ValueType& elem) - { - unique_lock<mutex> lk(mtx_, try_to_lock); - if (!lk.owns_lock()) - { - return false; - } - return try_pull(elem, lk); - } - template <typename ValueType> - boost::shared_ptr<ValueType> sync_queue<ValueType>::try_pull() - { - unique_lock<mutex> lk(mtx_); - return try_pull(lk); - } -#endif - template <typename ValueType> - queue_op_status sync_queue<ValueType>::nonblocking_pull_front(ValueType& elem) - { - unique_lock<mutex> lk(mtx_, try_to_lock); - if (!lk.owns_lock()) - { - return queue_op_status::busy; - } - return try_pull_front(elem, lk); - } - - template <typename ValueType> - void sync_queue<ValueType>::throw_if_closed(unique_lock<mutex>&) - { - if (closed_) - { - BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); - } - } - - template <typename ValueType> - void sync_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk) - { - for (;;) - { - if (! empty(lk)) break; - throw_if_closed(lk); - ++waiting_empty_; - not_empty_.wait(lk); - } - } - template <typename ValueType> - void sync_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed) - { - for (;;) - { - if (! empty(lk)) break; - if (closed_) {closed=true; return;} - ++waiting_empty_; - not_empty_.wait(lk); - } - closed=false; - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - void sync_queue<ValueType>::pull(ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - wait_until_not_empty(lk); - pull(elem, lk); - } - template <typename ValueType> - void sync_queue<ValueType>::pull(ValueType& elem, bool & closed) - { - unique_lock<mutex> lk(mtx_); - wait_until_not_empty(lk, closed); - if (closed) {return;} - pull(elem, lk); - } - - // enable if ValueType is nothrow movable - template <typename ValueType> - ValueType sync_queue<ValueType>::pull() - { - unique_lock<mutex> lk(mtx_); - wait_until_not_empty(lk); - return pull(lk); - } - template <typename ValueType> - boost::shared_ptr<ValueType> sync_queue<ValueType>::ptr_pull() - { - unique_lock<mutex> lk(mtx_); - wait_until_not_empty(lk); - return ptr_pull(lk); - } -#endif - - template <typename ValueType> - void sync_queue<ValueType>::pull_front(ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - wait_until_not_empty(lk); - pull_front(elem, lk); - } - - // enable if ValueType is nothrow movable - template <typename ValueType> - ValueType sync_queue<ValueType>::pull_front() - { - unique_lock<mutex> lk(mtx_); - wait_until_not_empty(lk); - return pull_front(lk); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk) - { - throw_if_closed(lk); - push(elem, lk); - return true; - } - - template <typename ValueType> - bool sync_queue<ValueType>::try_push(const ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - return try_push(elem, lk); - } -#endif - - template <typename ValueType> - queue_op_status sync_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk) - { - if (closed(lk)) return queue_op_status::closed; - push_back(elem, lk); - return queue_op_status::success; - } - - template <typename ValueType> - queue_op_status sync_queue<ValueType>::try_push_back(const ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - return try_push_back(elem, lk); - } - - template <typename ValueType> - queue_op_status sync_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk) - { - if (closed(lk)) return queue_op_status::closed; - push_back(elem, lk); - return queue_op_status::success; - } - - template <typename ValueType> - queue_op_status sync_queue<ValueType>::wait_push_back(const ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - return wait_push_back(elem, lk); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_queue<ValueType>::try_push(no_block_tag, const ValueType& elem) - { - unique_lock<mutex> lk(mtx_, try_to_lock); - if (!lk.owns_lock()) return false; - return try_push(elem, lk); - } -#endif - template <typename ValueType> - queue_op_status sync_queue<ValueType>::nonblocking_push_back(const ValueType& elem) - { - unique_lock<mutex> lk(mtx_, try_to_lock); - if (!lk.owns_lock()) return queue_op_status::busy; - return try_push_back(elem, lk); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - void sync_queue<ValueType>::push(const ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - throw_if_closed(lk); - push(elem, lk); - } -#endif - - template <typename ValueType> - void sync_queue<ValueType>::push_back(const ValueType& elem) - { - unique_lock<mutex> lk(mtx_); - throw_if_closed(lk); - push_back(elem, lk); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) - { - throw_if_closed(lk); - push(boost::move(elem), lk); - return true; - } - - template <typename ValueType> - bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_); - return try_push(boost::move(elem), lk); - } -#endif - - template <typename ValueType> - queue_op_status sync_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) - { - if (closed(lk)) return queue_op_status::closed; - push_back(boost::move(elem), lk); - return queue_op_status::success; - } - - template <typename ValueType> - queue_op_status sync_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_); - return try_push_back(boost::move(elem), lk); - } - - template <typename ValueType> - queue_op_status sync_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) - { - if (closed(lk)) return queue_op_status::closed; - push_back(boost::move(elem), lk); - return queue_op_status::success; - } - - template <typename ValueType> - queue_op_status sync_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_); - return wait_push_back(boost::move(elem), lk); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - bool sync_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_, try_to_lock); - if (!lk.owns_lock()) - { - return false; - } - return try_push(boost::move(elem), lk); - } -#endif - - template <typename ValueType> - queue_op_status sync_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_, try_to_lock); - if (!lk.owns_lock()) - { - return queue_op_status::busy; - } - return try_push_back(boost::move(elem), lk); - } - -#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD - template <typename ValueType> - void sync_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_); - throw_if_closed(lk); - push(boost::move(elem), lk); - } -#endif - - template <typename ValueType> - void sync_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem) - { - unique_lock<mutex> lk(mtx_); - throw_if_closed(lk); - push_back(boost::move(elem), lk); - } - - template <typename ValueType> - sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem) - { - sbq.push_back(boost::move(elem)); - return sbq; - } - - template <typename ValueType> - sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType const&elem) - { - sbq.push_back(elem); - return sbq; - } - - template <typename ValueType> - sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem) - { - sbq.pull_front(elem); - return sbq; - } - -} - -#include <boost/config/abi_suffix.hpp> +#include <boost/thread/concurrent_queues/sync_queue.hpp> #endif diff --git a/boost/thread/user_scheduler.hpp b/boost/thread/user_scheduler.hpp index 6305b9e26c..c551d21710 100644 --- a/boost/thread/user_scheduler.hpp +++ b/boost/thread/user_scheduler.hpp @@ -12,8 +12,8 @@ #include <boost/thread/detail/config.hpp> #include <boost/thread/detail/delete.hpp> #include <boost/thread/detail/move.hpp> -#include <boost/thread/sync_queue.hpp> -#include <boost/thread/detail/work.hpp> +#include <boost/thread/concurrent_queues/sync_queue.hpp> +#include <boost/thread/executors/work.hpp> #include <boost/config/abi_prefix.hpp> @@ -39,7 +39,7 @@ namespace boost work task; try { - if (work_queue.try_pull_front(task) == queue_op_status::success) + if (work_queue.try_pull(task) == queue_op_status::success) { task(); return true; @@ -144,23 +144,23 @@ namespace boost void submit(Closure & closure) { work w ((closure)); - work_queue.push_back(boost::move(w)); + work_queue.push(boost::move(w)); //work_queue.push(work(closure)); // todo check why this doesn't work } #endif void submit(void (*closure)()) { work w ((closure)); - work_queue.push_back(boost::move(w)); - //work_queue.push_back(work(closure)); // todo check why this doesn't work + work_queue.push(boost::move(w)); + //work_queue.push(work(closure)); // todo check why this doesn't work } template <typename Closure> void submit(BOOST_THREAD_RV_REF(Closure) closure) { work w =boost::move(closure); - work_queue.push_back(boost::move(w)); - //work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work + work_queue.push(boost::move(w)); + //work_queue.push(work(boost::move(closure))); // todo check why this doesn't work } /** diff --git a/boost/thread/win32/thread_primitives.hpp b/boost/thread/win32/thread_primitives.hpp index 2960822f65..d9f63e6cf4 100644 --- a/boost/thread/win32/thread_primitives.hpp +++ b/boost/thread/win32/thread_primitives.hpp @@ -285,7 +285,6 @@ namespace boost // Oops, we weren't called often enough, we're stuck return 0xFFFFFFFF; } -#else #endif inline detail::gettickcount64_t GetTickCount64_() { |