1 // (C) Copyright 2012 Vicente J. Botet Escriba
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
7 #ifndef BOOST_THREAD_TESTABLE_LOCKABLE_HPP
8 #define BOOST_THREAD_TESTABLE_LOCKABLE_HPP
10 #include <boost/thread/detail/config.hpp>
12 #include <boost/thread/thread_only.hpp>
14 #include <boost/atomic.hpp>
15 #include <boost/assert.hpp>
17 #include <boost/config/abi_prefix.hpp>
22 * Based on Associate Mutexes with Data to Prevent Races, By Herb Sutter, May 13, 2010
23 * http://www.drdobbs.com/windows/associate-mutexes-with-data-to-prevent-r/224701827?pgno=3
25 * Make our mutex testable if it isn't already.
27 * Many mutex services (including boost::mutex) don't provide a way to ask,
28 * "Do I already hold a lock on this mutex?"
29 * Sometimes it is needed to know if a method like is_locked to be available.
30 * This wrapper associates an arbitrary lockable type with a thread id that stores the ID of the thread that
31 * currently holds the lockable. The thread id initially holds an invalid value that means no threads own the mutex.
32 * 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.
35 template <typename Lockable>
39 atomic<thread::id> id_;
41 /// the type of the wrapped lockable
42 typedef Lockable lockable_type;
45 BOOST_THREAD_NO_COPYABLE(testable_mutex)
47 testable_mutex() : id_(thread::id()) {}
51 BOOST_ASSERT(! is_locked_by_this_thread());
53 id_ = this_thread::get_id();
58 BOOST_ASSERT(is_locked_by_this_thread());
65 BOOST_ASSERT(! is_locked_by_this_thread());
68 id_ = this_thread::get_id();
76 #ifdef BOOST_THREAD_USES_CHRONO
77 template <class Rep, class Period>
78 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
80 BOOST_ASSERT(! is_locked_by_this_thread());
81 if (mtx_.try_lock_for(rel_time))
83 id_ = this_thread::get_id();
91 template <class Clock, class Duration>
92 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
94 BOOST_ASSERT(! is_locked_by_this_thread());
95 if (mtx_.try_lock_until(abs_time))
97 id_ = this_thread::get_id();
107 bool is_locked_by_this_thread() const
109 return this_thread::get_id() == id_;
111 bool is_locked() const
113 return ! (thread::id() == id_);
116 thread::id get_id() const
121 // todo add the shared and upgrade mutex functions
124 template <typename Lockable>
125 struct is_testable_lockable : false_type
128 template <typename Lockable>
129 struct is_testable_lockable<testable_mutex<Lockable> > : true_type
133 // * Overloaded function used to check if the mutex is locked when it is testable and do nothing otherwise.
135 // * This function is used usually to assert the pre-condition when the function can only be called when the mutex
136 // * must be locked by the current thread.
138 // template <typename Lockable>
139 // bool is_locked_by_this_thread(testable_mutex<Lockable> const& mtx)
141 // return mtx.is_locked();
143 // template <typename Lockable>
144 // bool is_locked_by_this_thread(Lockable const&)
150 #include <boost/config/abi_suffix.hpp>