interprocess_sharable_mutex.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. //////////////////////////////////////////////////////////////////////////////
  2. // Code based on Howard Hinnant's shared_mutex class
  3. //
  4. // (C) Copyright Howard Hinnant 2007-2010. Distributed under the Boost
  5. // Software License, Version 1.0. (see http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
  8. // Software License, Version 1.0. (See accompanying file
  9. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // See http://www.boost.org/libs/interprocess for documentation.
  12. //
  13. //////////////////////////////////////////////////////////////////////////////
  14. #ifndef BOOST_INTERPROCESS_SHARABLE_MUTEX_HPP
  15. #define BOOST_INTERPROCESS_SHARABLE_MUTEX_HPP
  16. #if (defined _MSC_VER) && (_MSC_VER >= 1200)
  17. # pragma once
  18. #endif
  19. #include <boost/interprocess/detail/config_begin.hpp>
  20. #include <boost/interprocess/detail/workaround.hpp>
  21. #include <boost/interprocess/sync/scoped_lock.hpp>
  22. #include <boost/interprocess/detail/posix_time_types_wrk.hpp>
  23. #include <boost/interprocess/sync/interprocess_mutex.hpp>
  24. #include <boost/interprocess/sync/interprocess_condition.hpp>
  25. #include <climits>
  26. //!\file
  27. //!Describes interprocess_sharable_mutex class
  28. namespace boost {
  29. namespace interprocess {
  30. //!Wraps a interprocess_sharable_mutex that can be placed in shared memory and can be
  31. //!shared between processes. Allows timed lock tries
  32. class interprocess_sharable_mutex
  33. {
  34. //Non-copyable
  35. interprocess_sharable_mutex(const interprocess_sharable_mutex &);
  36. interprocess_sharable_mutex &operator=(const interprocess_sharable_mutex &);
  37. friend class interprocess_condition;
  38. public:
  39. //!Constructs the sharable lock.
  40. //!Throws interprocess_exception on error.
  41. interprocess_sharable_mutex();
  42. //!Destroys the sharable lock.
  43. //!Does not throw.
  44. ~interprocess_sharable_mutex();
  45. //Exclusive locking
  46. //!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
  47. //! and if another thread has exclusive or sharable ownership of
  48. //! the mutex, it waits until it can obtain the ownership.
  49. //!Throws: interprocess_exception on error.
  50. void lock();
  51. //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
  52. //! without waiting. If no other thread has exclusive or sharable
  53. //! ownership of the mutex this succeeds.
  54. //!Returns: If it can acquire exclusive ownership immediately returns true.
  55. //! If it has to wait, returns false.
  56. //!Throws: interprocess_exception on error.
  57. bool try_lock();
  58. //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
  59. //! waiting if necessary until no other thread has exclusive or sharable
  60. //! ownership of the mutex or abs_time is reached.
  61. //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
  62. //!Throws: interprocess_exception on error.
  63. bool timed_lock(const boost::posix_time::ptime &abs_time);
  64. //!Precondition: The thread must have exclusive ownership of the mutex.
  65. //!Effects: The calling thread releases the exclusive ownership of the mutex.
  66. //!Throws: An exception derived from interprocess_exception on error.
  67. void unlock();
  68. //Sharable locking
  69. //!Effects: The calling thread tries to obtain sharable ownership of the mutex,
  70. //! and if another thread has exclusive ownership of the mutex,
  71. //! waits until it can obtain the ownership.
  72. //!Throws: interprocess_exception on error.
  73. void lock_sharable();
  74. //!Effects: The calling thread tries to acquire sharable ownership of the mutex
  75. //! without waiting. If no other thread has exclusive ownership
  76. //! of the mutex this succeeds.
  77. //!Returns: If it can acquire sharable ownership immediately returns true. If it
  78. //! has to wait, returns false.
  79. //!Throws: interprocess_exception on error.
  80. bool try_lock_sharable();
  81. //!Effects: The calling thread tries to acquire sharable ownership of the mutex
  82. //! waiting if necessary until no other thread has exclusive
  83. //! ownership of the mutex or abs_time is reached.
  84. //!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
  85. //!Throws: interprocess_exception on error.
  86. bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
  87. //!Precondition: The thread must have sharable ownership of the mutex.
  88. //!Effects: The calling thread releases the sharable ownership of the mutex.
  89. //!Throws: An exception derived from interprocess_exception on error.
  90. void unlock_sharable();
  91. /// @cond
  92. private:
  93. typedef scoped_lock<interprocess_mutex> scoped_lock_t;
  94. //Pack all the control data in a word to be able
  95. //to use atomic instructions in the future
  96. struct control_word_t
  97. {
  98. unsigned exclusive_in : 1;
  99. unsigned num_shared : sizeof(unsigned)*CHAR_BIT-1;
  100. } m_ctrl;
  101. interprocess_mutex m_mut;
  102. interprocess_condition m_first_gate;
  103. interprocess_condition m_second_gate;
  104. private:
  105. //Rollback structures for exceptions or failure return values
  106. struct exclusive_rollback
  107. {
  108. exclusive_rollback(control_word_t &ctrl
  109. ,interprocess_condition &first_gate)
  110. : mp_ctrl(&ctrl), m_first_gate(first_gate)
  111. {}
  112. void release()
  113. { mp_ctrl = 0; }
  114. ~exclusive_rollback()
  115. {
  116. if(mp_ctrl){
  117. mp_ctrl->exclusive_in = 0;
  118. m_first_gate.notify_all();
  119. }
  120. }
  121. control_word_t *mp_ctrl;
  122. interprocess_condition &m_first_gate;
  123. };
  124. template<int Dummy>
  125. struct base_constants_t
  126. {
  127. static const unsigned max_readers
  128. = ~(unsigned(1) << (sizeof(unsigned)*CHAR_BIT-1));
  129. };
  130. typedef base_constants_t<0> constants;
  131. /// @endcond
  132. };
  133. /// @cond
  134. template <int Dummy>
  135. const unsigned interprocess_sharable_mutex::base_constants_t<Dummy>::max_readers;
  136. inline interprocess_sharable_mutex::interprocess_sharable_mutex()
  137. {
  138. this->m_ctrl.exclusive_in = 0;
  139. this->m_ctrl.num_shared = 0;
  140. }
  141. inline interprocess_sharable_mutex::~interprocess_sharable_mutex()
  142. {}
  143. inline void interprocess_sharable_mutex::lock()
  144. {
  145. scoped_lock_t lck(m_mut);
  146. //The exclusive lock must block in the first gate
  147. //if an exclusive lock has been acquired
  148. while (this->m_ctrl.exclusive_in){
  149. this->m_first_gate.wait(lck);
  150. }
  151. //Mark that exclusive lock has been acquired
  152. this->m_ctrl.exclusive_in = 1;
  153. //Prepare rollback
  154. exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
  155. //Now wait until all readers are gone
  156. while (this->m_ctrl.num_shared){
  157. this->m_second_gate.wait(lck);
  158. }
  159. rollback.release();
  160. }
  161. inline bool interprocess_sharable_mutex::try_lock()
  162. {
  163. scoped_lock_t lck(m_mut, try_to_lock);
  164. //If we can't lock or any has there is any exclusive
  165. //or sharable mark return false;
  166. if(!lck.owns()
  167. || this->m_ctrl.exclusive_in
  168. || this->m_ctrl.num_shared){
  169. return false;
  170. }
  171. this->m_ctrl.exclusive_in = 1;
  172. return true;
  173. }
  174. inline bool interprocess_sharable_mutex::timed_lock
  175. (const boost::posix_time::ptime &abs_time)
  176. {
  177. if(abs_time == boost::posix_time::pos_infin){
  178. this->lock();
  179. return true;
  180. }
  181. scoped_lock_t lck(m_mut, abs_time);
  182. if(!lck.owns()) return false;
  183. //The exclusive lock must block in the first gate
  184. //if an exclusive lock has been acquired
  185. while (this->m_ctrl.exclusive_in){
  186. if(!this->m_first_gate.timed_wait(lck, abs_time)){
  187. if(this->m_ctrl.exclusive_in){
  188. return false;
  189. }
  190. break;
  191. }
  192. }
  193. //Mark that exclusive lock has been acquired
  194. this->m_ctrl.exclusive_in = 1;
  195. //Prepare rollback
  196. exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
  197. //Now wait until all readers are gone
  198. while (this->m_ctrl.num_shared){
  199. if(!this->m_second_gate.timed_wait(lck, abs_time)){
  200. if(this->m_ctrl.num_shared){
  201. return false;
  202. }
  203. break;
  204. }
  205. }
  206. rollback.release();
  207. return true;
  208. }
  209. inline void interprocess_sharable_mutex::unlock()
  210. {
  211. scoped_lock_t lck(m_mut);
  212. this->m_ctrl.exclusive_in = 0;
  213. this->m_first_gate.notify_all();
  214. }
  215. //Sharable locking
  216. inline void interprocess_sharable_mutex::lock_sharable()
  217. {
  218. scoped_lock_t lck(m_mut);
  219. //The sharable lock must block in the first gate
  220. //if an exclusive lock has been acquired
  221. //or there are too many sharable locks
  222. while(this->m_ctrl.exclusive_in
  223. || this->m_ctrl.num_shared == constants::max_readers){
  224. this->m_first_gate.wait(lck);
  225. }
  226. //Increment sharable count
  227. ++this->m_ctrl.num_shared;
  228. }
  229. inline bool interprocess_sharable_mutex::try_lock_sharable()
  230. {
  231. scoped_lock_t lck(m_mut, try_to_lock);
  232. //The sharable lock must fail
  233. //if an exclusive lock has been acquired
  234. //or there are too many sharable locks
  235. if(!lck.owns()
  236. || this->m_ctrl.exclusive_in
  237. || this->m_ctrl.num_shared == constants::max_readers){
  238. return false;
  239. }
  240. //Increment sharable count
  241. ++this->m_ctrl.num_shared;
  242. return true;
  243. }
  244. inline bool interprocess_sharable_mutex::timed_lock_sharable
  245. (const boost::posix_time::ptime &abs_time)
  246. {
  247. if(abs_time == boost::posix_time::pos_infin){
  248. this->lock_sharable();
  249. return true;
  250. }
  251. scoped_lock_t lck(m_mut, abs_time);
  252. if(!lck.owns()) return false;
  253. //The sharable lock must block in the first gate
  254. //if an exclusive lock has been acquired
  255. //or there are too many sharable locks
  256. while (this->m_ctrl.exclusive_in
  257. || this->m_ctrl.num_shared == constants::max_readers){
  258. if(!this->m_first_gate.timed_wait(lck, abs_time)){
  259. if(this->m_ctrl.exclusive_in
  260. || this->m_ctrl.num_shared == constants::max_readers){
  261. return false;
  262. }
  263. break;
  264. }
  265. }
  266. //Increment sharable count
  267. ++this->m_ctrl.num_shared;
  268. return true;
  269. }
  270. inline void interprocess_sharable_mutex::unlock_sharable()
  271. {
  272. scoped_lock_t lck(m_mut);
  273. //Decrement sharable count
  274. --this->m_ctrl.num_shared;
  275. if (this->m_ctrl.num_shared == 0){
  276. this->m_second_gate.notify_one();
  277. }
  278. //Check if there are blocked sharables because of
  279. //there were too many sharables
  280. else if(this->m_ctrl.num_shared == (constants::max_readers-1)){
  281. this->m_first_gate.notify_all();
  282. }
  283. }
  284. /// @endcond
  285. } //namespace interprocess {
  286. } //namespace boost {
  287. #include <boost/interprocess/detail/config_end.hpp>
  288. #endif //BOOST_INTERPROCESS_SHARABLE_MUTEX_HPP