diff --git a/README.mkd b/README.mkd new file mode 100644 index 0000000..0a860b5 --- /dev/null +++ b/README.mkd @@ -0,0 +1,27 @@ +Mutable Threads +=============== + +Introduction: +------------- + +> Mutable Threads is an simple implementation of n3356 proposal. + +Depends: +-------- + +> Mutable Threads depends on followings. +> +> * [Boost](http://www.boost.org/) 1.49.0 or later + +License: +-------- + + Copyright Kohei Takahashi 2012. + 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) + +Author: +------- + +> * Kohei Takahashi (flast@flast.jp) diff --git a/mutable_thread/detail/exception.hpp b/mutable_thread/detail/exception.hpp new file mode 100644 index 0000000..b30b156 --- /dev/null +++ b/mutable_thread/detail/exception.hpp @@ -0,0 +1,27 @@ +// Copyright Kohei Takahashi 2012. +// 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 MUTABLE_THREAD_DETAIL_EXCEPTION_HPP_ +#define MUTABLE_THREAD_DETAIL_EXCEPTION_HPP_ + +#include +#include +#include + +namespace mutable_threads { namespace detail { + +struct mutable_thread_exception : public std::logic_error +{ + explicit + mutable_thread_exception(const std::string &message) + : std::logic_error(message) + { + } +}; // struct mutable_thread_exception + +} } // namespace mutable_threads::detail + +#endif // MUTABLE_THREAD_DETAIL_EXCEPTION_HPP_ + diff --git a/mutable_thread/detail/n3356.hpp b/mutable_thread/detail/n3356.hpp new file mode 100644 index 0000000..fe351e2 --- /dev/null +++ b/mutable_thread/detail/n3356.hpp @@ -0,0 +1,224 @@ +// Copyright Kohei Takahashi 2012. +// 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 MUTABLE_THREAD_DETAIL_N3356_HPP_ +#define MUTABLE_THREAD_DETAIL_N3356_HPP_ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace mutable_threads { namespace n3356 { + +class mutable_thread : private boost::thread +{ + typedef mutable_thread this_type; + typedef boost::thread thread_type; + typedef boost::function function_type; + + BOOST_MOVABLE_BUT_NOT_COPYABLE(mutable_thread) + + static void + S_thraed_main_(mutable_thread *this_, boost::barrier *barrier) + { + boost::shared_ptr term = this_->m_term_; + boost::shared_ptr mutex = this_->m_mutex_; + boost::shared_ptr cond = this_->m_cond_; + boost::shared_ptr func = this_->m_func_; + + typedef boost::unique_lock lock_type; + + while (true) + { + lock_type guard(*mutex); + if (barrier) + { + barrier->wait(); + barrier = NULL; + } + while (func->empty()) + { + if (*term) { return; } // terminate + cond->wait(guard); + } + + (*func)(); + func->clear(); + } + } + +public: + mutable_thread() + : m_term_(boost::make_shared(false)) + , m_mutex_(boost::make_shared()) + , m_cond_(boost::make_shared()) + , m_func_(boost::make_shared()) + { + boost::barrier b(2); + thread_type(S_thraed_main_, this, &b).swap(*this); + b.wait(); + } + + mutable_thread(BOOST_RV_REF(mutable_thread) other) BOOST_NOEXCEPT + : thread_type(boost::move(static_cast(other))) + , m_term_(boost::move(other.m_term_)) + , m_mutex_(boost::move(other.m_mutex_)) + , m_cond_(boost::move(other.m_cond_)) + , m_func_(boost::move(other.m_func_)) + { + other.m_term_.reset(); + other.m_mutex_.reset(); + other.m_cond_.reset(); + other.m_func_.reset(); + } + + template + explicit + mutable_thread(F f) + : m_term_(boost::make_shared(false)) + , m_mutex_(boost::make_shared()) + , m_cond_(boost::make_shared()) + , m_func_(boost::make_shared(f)) + { + boost::barrier b(2); + thread_type(S_thraed_main_, this, &b).swap(*this); + b.wait(); + } + + mutable_thread & + operator=(BOOST_RV_REF(mutable_thread) other) BOOST_NOEXCEPT + { + mutable_thread(boost::move(other)).swap(*this); + return *this; + } + + void + join() + { + if (!joinable()) + { + BOOST_THROW_EXCEPTION( + detail::mutable_thread_exception("\"!joinable()\" failed")); + } + + typedef boost::unique_lock lock_type; + if (lock_type guard = lock_type(*m_mutex_)) + { + *m_term_ = true; + m_cond_->notify_one(); + + m_mutex_.reset(); + m_cond_.reset(); + m_func_.reset(); + } + thread_type::join(); + m_term_.reset(); + } + + using thread_type::joinable; + + template + bool + try_execute(F f) + { + typedef boost::unique_lock lock_type; + + if (is_done() || is_joining()) + { + BOOST_THROW_EXCEPTION( + boost::lock_error( + boost::system::errc::operation_not_permitted + , "\"!is_done() && !is_joining()\" failed")); + } + + if (lock_type guard = lock_type(*m_mutex_, boost::try_to_lock)) + { + if (is_done() || is_joining()) { return false; } + + BOOST_ASSERT(m_func_->empty()); + *m_func_ = f; + m_cond_->notify_one(); + return true; + } + return false; + } + + template + bool + execute(F f) + { + typedef boost::unique_lock lock_type; + + if (is_done() || is_joining()) + { + BOOST_THROW_EXCEPTION( + boost::lock_error( + boost::system::errc::operation_not_permitted + , "\"!is_done() && !is_joining()\" failed")); + } + + if (lock_type guard = lock_type(*m_mutex_)) + { + if (is_done() || is_joining()) { return false; } + + BOOST_ASSERT(m_func_->empty()); + *m_func_ = f; + m_cond_->notify_one(); + return true; + } + return false; + } + + bool + is_joining() const BOOST_NOEXCEPT + { + return !m_mutex_ && !m_cond_ && !m_func_ && joinable(); + } + + bool + is_done() const BOOST_NOEXCEPT + { + return !m_mutex_ && !m_cond_ && !m_func_ && !joinable(); + } + + using thread_type::id; + using thread_type::get_id; + using thread_type::native_handle; + + void + swap(mutable_thread &other) BOOST_NOEXCEPT + { + thread_type::swap(other); + boost::swap(m_term_ , other.m_term_ ); + boost::swap(m_mutex_, other.m_mutex_); + boost::swap(m_cond_ , other.m_cond_ ); + boost::swap(m_func_ , other.m_func_ ); + } + +private: + boost::shared_ptr m_term_; + boost::shared_ptr m_mutex_; + boost::shared_ptr m_cond_; + boost::shared_ptr m_func_; +}; // class mutable_thread + +} } // namespace mutable_threads::n3356 + +#endif // MUTABLE_THREAD_DETAIL_N3356_HPP_ + diff --git a/mutable_thread/mutable_thread.hpp b/mutable_thread/mutable_thread.hpp new file mode 100644 index 0000000..5b9efcc --- /dev/null +++ b/mutable_thread/mutable_thread.hpp @@ -0,0 +1,13 @@ +// Copyright Kohei Takahashi 2012. +// 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 MUTABLE_THREAD_MUTABLE_THREAD_HPP_ +#define MUTABLE_THREAD_MUTABLE_THREAD_HPP_ + +#include +#include + +#endif // MUTABLE_THREAD_MUTABLE_THREAD_HPP_ + diff --git a/mutable_thread/mutable_thread_fwd.hpp b/mutable_thread/mutable_thread_fwd.hpp new file mode 100644 index 0000000..5e0ff5c --- /dev/null +++ b/mutable_thread/mutable_thread_fwd.hpp @@ -0,0 +1,23 @@ +// Copyright Kohei Takahashi 2012. +// 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 MUTABLE_THREAD_MUTABLE_THREAD_FWD_HPP_ +#define MUTABLE_THREAD_MUTABLE_THREAD_FWD_HPP_ + +namespace mutable_threads { + +namespace n3356 { + +class mutable_thread; + +} // namespace mutable_threads::n3356 + +// Use n3356's implementation by default. +using namespace n3356; + +} // namespace mutable_threads + +#endif // MUTABLE_THREAD_MUTABLE_THREAD_FWD_HPP_ +