testable_mutex.hpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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)
  5. #ifndef BOOST_THREAD_TESTABLE_LOCKABLE_HPP
  6. #define BOOST_THREAD_TESTABLE_LOCKABLE_HPP
  7. #include <boost/thread/detail/config.hpp>
  8. #include <boost/thread/thread_only.hpp>
  9. #include <boost/atomic.hpp>
  10. #include <boost/assert.hpp>
  11. #include <boost/config/abi_prefix.hpp>
  12. namespace boost
  13. {
  14. /**
  15. * Based on Associate Mutexes with Data to Prevent Races, By Herb Sutter, May 13, 2010
  16. * http://www.drdobbs.com/windows/associate-mutexes-with-data-to-prevent-r/224701827?pgno=3
  17. *
  18. * Make our mutex testable if it isn't already.
  19. *
  20. * Many mutex services (including boost::mutex) don't provide a way to ask,
  21. * "Do I already hold a lock on this mutex?"
  22. * Sometimes it is needed to know if a method like is_locked to be available.
  23. * This wrapper associates an arbitrary lockable type with a thread id that stores the ID of the thread that
  24. * currently holds the lockable. The thread id initially holds an invalid value that means no threads own the mutex.
  25. * 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.
  26. *
  27. */
  28. template <typename Lockable>
  29. class testable_mutex
  30. {
  31. Lockable mtx_;
  32. atomic<thread::id> id_;
  33. public:
  34. /// the type of the wrapped lockable
  35. typedef Lockable lockable_type;
  36. /// Non copyable
  37. BOOST_THREAD_NO_COPYABLE(testable_mutex)
  38. testable_mutex() : id_(thread::id()) {}
  39. void lock()
  40. {
  41. BOOST_ASSERT(! is_locked_by_this_thread());
  42. mtx_.lock();
  43. id_ = this_thread::get_id();
  44. }
  45. void unlock()
  46. {
  47. BOOST_ASSERT(is_locked_by_this_thread());
  48. id_ = thread::id();
  49. mtx_.unlock();
  50. }
  51. bool try_lock()
  52. {
  53. BOOST_ASSERT(! is_locked_by_this_thread());
  54. if (mtx_.try_lock())
  55. {
  56. id_ = this_thread::get_id();
  57. return true;
  58. }
  59. else
  60. {
  61. return false;
  62. }
  63. }
  64. #ifdef BOOST_THREAD_USES_CHRONO
  65. template <class Rep, class Period>
  66. bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
  67. {
  68. BOOST_ASSERT(! is_locked_by_this_thread());
  69. if (mtx_.try_lock_for(rel_time))
  70. {
  71. id_ = this_thread::get_id();
  72. return true;
  73. }
  74. else
  75. {
  76. return false;
  77. }
  78. }
  79. template <class Clock, class Duration>
  80. bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
  81. {
  82. BOOST_ASSERT(! is_locked_by_this_thread());
  83. if (mtx_.try_lock_until(abs_time))
  84. {
  85. id_ = this_thread::get_id();
  86. return true;
  87. }
  88. else
  89. {
  90. return false;
  91. }
  92. }
  93. #endif
  94. bool is_locked_by_this_thread() const
  95. {
  96. return this_thread::get_id() == id_;
  97. }
  98. bool is_locked() const
  99. {
  100. return ! (thread::id() == id_);
  101. }
  102. thread::id get_id() const
  103. {
  104. return id_;
  105. }
  106. // todo add the shared and upgrade mutex functions
  107. };
  108. template <typename Lockable>
  109. struct is_testable_lockable : false_type
  110. {};
  111. template <typename Lockable>
  112. struct is_testable_lockable<testable_mutex<Lockable> > : true_type
  113. {};
  114. // /**
  115. // * Overloaded function used to check if the mutex is locked when it is testable and do nothing otherwise.
  116. // *
  117. // * This function is used usually to assert the pre-condition when the function can only be called when the mutex
  118. // * must be locked by the current thread.
  119. // */
  120. // template <typename Lockable>
  121. // bool is_locked_by_this_thread(testable_mutex<Lockable> const& mtx)
  122. // {
  123. // return mtx.is_locked();
  124. // }
  125. // template <typename Lockable>
  126. // bool is_locked_by_this_thread(Lockable const&)
  127. // {
  128. // return true;
  129. // }
  130. }
  131. #include <boost/config/abi_suffix.hpp>
  132. #endif // header