123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- // (C) Copyright 2012 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_TESTABLE_LOCKABLE_HPP
- #define BOOST_THREAD_TESTABLE_LOCKABLE_HPP
- #include <boost/thread/detail/config.hpp>
- #include <boost/thread/thread_only.hpp>
- #include <boost/atomic.hpp>
- #include <boost/assert.hpp>
- #include <boost/config/abi_prefix.hpp>
- namespace boost
- {
- /**
- * Based on Associate Mutexes with Data to Prevent Races, By Herb Sutter, May 13, 2010
- * http://www.drdobbs.com/windows/associate-mutexes-with-data-to-prevent-r/224701827?pgno=3
- *
- * Make our mutex testable if it isn't already.
- *
- * Many mutex services (including boost::mutex) don't provide a way to ask,
- * "Do I already hold a lock on this mutex?"
- * Sometimes it is needed to know if a method like is_locked to be available.
- * This wrapper associates an arbitrary lockable type with a thread id that stores the ID of the thread that
- * currently holds the lockable. The thread id initially holds an invalid value that means no threads own the mutex.
- * When we acquire a lock, we set the thread id; and when we release a lock, we reset it back to its default no id state.
- *
- */
- template <typename Lockable>
- class testable_mutex
- {
- Lockable mtx_;
- atomic<thread::id> id_;
- public:
- /// the type of the wrapped lockable
- typedef Lockable lockable_type;
- /// Non copyable
- BOOST_THREAD_NO_COPYABLE(testable_mutex)
- testable_mutex() : id_(thread::id()) {}
- void lock()
- {
- BOOST_ASSERT(! is_locked_by_this_thread());
- mtx_.lock();
- id_ = this_thread::get_id();
- }
- void unlock()
- {
- BOOST_ASSERT(is_locked_by_this_thread());
- id_ = thread::id();
- mtx_.unlock();
- }
- bool try_lock()
- {
- BOOST_ASSERT(! is_locked_by_this_thread());
- if (mtx_.try_lock())
- {
- id_ = this_thread::get_id();
- return true;
- }
- else
- {
- return false;
- }
- }
- #ifdef BOOST_THREAD_USES_CHRONO
- template <class Rep, class Period>
- bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
- {
- BOOST_ASSERT(! is_locked_by_this_thread());
- if (mtx_.try_lock_for(rel_time))
- {
- id_ = this_thread::get_id();
- return true;
- }
- else
- {
- return false;
- }
- }
- template <class Clock, class Duration>
- bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
- {
- BOOST_ASSERT(! is_locked_by_this_thread());
- if (mtx_.try_lock_until(abs_time))
- {
- id_ = this_thread::get_id();
- return true;
- }
- else
- {
- return false;
- }
- }
- #endif
- bool is_locked_by_this_thread() const
- {
- return this_thread::get_id() == id_;
- }
- bool is_locked() const
- {
- return ! (thread::id() == id_);
- }
- thread::id get_id() const
- {
- return id_;
- }
- // todo add the shared and upgrade mutex functions
- };
- template <typename Lockable>
- struct is_testable_lockable : false_type
- {};
- template <typename Lockable>
- struct is_testable_lockable<testable_mutex<Lockable> > : true_type
- {};
- // /**
- // * Overloaded function used to check if the mutex is locked when it is testable and do nothing otherwise.
- // *
- // * This function is used usually to assert the pre-condition when the function can only be called when the mutex
- // * must be locked by the current thread.
- // */
- // template <typename Lockable>
- // bool is_locked_by_this_thread(testable_mutex<Lockable> const& mtx)
- // {
- // return mtx.is_locked();
- // }
- // template <typename Lockable>
- // bool is_locked_by_this_thread(Lockable const&)
- // {
- // return true;
- // }
- }
- #include <boost/config/abi_suffix.hpp>
- #endif // header
|