shared_mutex.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. #ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
  2. #define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
  3. // (C) Copyright 2006-8 Anthony Williams
  4. // (C) Copyright 2012 Vicente J. Botet Escriba
  5. //
  6. // Distributed under the Boost Software License, Version 1.0. (See
  7. // accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. #include <boost/assert.hpp>
  10. #include <boost/bind/bind.hpp>
  11. #include <boost/static_assert.hpp>
  12. #include <boost/thread/mutex.hpp>
  13. #include <boost/thread/condition_variable.hpp>
  14. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  15. #include <boost/thread/detail/thread_interruption.hpp>
  16. #endif
  17. #ifdef BOOST_THREAD_USES_CHRONO
  18. #include <boost/chrono/system_clocks.hpp>
  19. #include <boost/chrono/ceil.hpp>
  20. #endif
  21. #include <boost/thread/detail/delete.hpp>
  22. #include <boost/config/abi_prefix.hpp>
  23. namespace boost
  24. {
  25. class shared_mutex
  26. {
  27. private:
  28. class state_data
  29. {
  30. public:
  31. state_data () :
  32. shared_count(0),
  33. exclusive(false),
  34. upgrade(false),
  35. exclusive_waiting_blocked(false)
  36. {}
  37. void assert_free() const
  38. {
  39. BOOST_ASSERT( ! exclusive );
  40. BOOST_ASSERT( ! upgrade );
  41. BOOST_ASSERT( shared_count==0 );
  42. }
  43. void assert_locked() const
  44. {
  45. BOOST_ASSERT( exclusive );
  46. BOOST_ASSERT( shared_count==0 );
  47. BOOST_ASSERT( ! upgrade );
  48. }
  49. void assert_lock_shared () const
  50. {
  51. BOOST_ASSERT( ! exclusive );
  52. BOOST_ASSERT( shared_count>0 );
  53. //BOOST_ASSERT( (! upgrade) || (shared_count>1));
  54. // if upgraded there are at least 2 threads sharing the mutex,
  55. // except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership.
  56. }
  57. void assert_lock_upgraded () const
  58. {
  59. BOOST_ASSERT( ! exclusive );
  60. BOOST_ASSERT( upgrade );
  61. BOOST_ASSERT( shared_count>0 );
  62. }
  63. void assert_lock_not_upgraded () const
  64. {
  65. BOOST_ASSERT( ! upgrade );
  66. }
  67. bool can_lock () const
  68. {
  69. return ! (shared_count || exclusive);
  70. }
  71. void lock ()
  72. {
  73. exclusive = true;
  74. }
  75. void unlock ()
  76. {
  77. exclusive = false;
  78. exclusive_waiting_blocked = false;
  79. }
  80. bool can_lock_shared () const
  81. {
  82. return ! (exclusive || exclusive_waiting_blocked);
  83. }
  84. bool no_shared () const
  85. {
  86. return shared_count==0;
  87. }
  88. bool one_shared () const
  89. {
  90. return shared_count==1;
  91. }
  92. void lock_shared ()
  93. {
  94. ++shared_count;
  95. }
  96. void unlock_shared ()
  97. {
  98. --shared_count;
  99. }
  100. void lock_upgrade ()
  101. {
  102. ++shared_count;
  103. upgrade=true;
  104. }
  105. bool can_lock_upgrade () const
  106. {
  107. return ! (exclusive || exclusive_waiting_blocked || upgrade);
  108. }
  109. void unlock_upgrade ()
  110. {
  111. upgrade=false;
  112. --shared_count;
  113. }
  114. //private:
  115. unsigned shared_count;
  116. bool exclusive;
  117. bool upgrade;
  118. bool exclusive_waiting_blocked;
  119. };
  120. state_data state;
  121. boost::mutex state_change;
  122. boost::condition_variable shared_cond;
  123. boost::condition_variable exclusive_cond;
  124. boost::condition_variable upgrade_cond;
  125. void release_waiters()
  126. {
  127. exclusive_cond.notify_one();
  128. shared_cond.notify_all();
  129. }
  130. public:
  131. BOOST_THREAD_NO_COPYABLE(shared_mutex)
  132. shared_mutex()
  133. {
  134. }
  135. ~shared_mutex()
  136. {
  137. }
  138. void lock_shared()
  139. {
  140. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  141. boost::this_thread::disable_interruption do_not_disturb;
  142. #endif
  143. boost::unique_lock<boost::mutex> lk(state_change);
  144. shared_cond.wait(lk, boost::bind(&state_data::can_lock_shared, boost::ref(state)));
  145. state.lock_shared();
  146. }
  147. bool try_lock_shared()
  148. {
  149. boost::unique_lock<boost::mutex> lk(state_change);
  150. if(!state.can_lock_shared())
  151. {
  152. return false;
  153. }
  154. state.lock_shared();
  155. return true;
  156. }
  157. #if defined BOOST_THREAD_USES_DATETIME
  158. bool timed_lock_shared(system_time const& timeout)
  159. {
  160. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  161. boost::this_thread::disable_interruption do_not_disturb;
  162. #endif
  163. boost::unique_lock<boost::mutex> lk(state_change);
  164. if(!shared_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock_shared, boost::ref(state))))
  165. {
  166. return false;
  167. }
  168. state.lock_shared();
  169. return true;
  170. }
  171. template<typename TimeDuration>
  172. bool timed_lock_shared(TimeDuration const & relative_time)
  173. {
  174. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  175. boost::this_thread::disable_interruption do_not_disturb;
  176. #endif
  177. boost::unique_lock<boost::mutex> lk(state_change);
  178. if(!shared_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock_shared, boost::ref(state))))
  179. {
  180. return false;
  181. }
  182. state.lock_shared();
  183. return true;
  184. }
  185. #endif
  186. #ifdef BOOST_THREAD_USES_CHRONO
  187. template <class Rep, class Period>
  188. bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
  189. {
  190. return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
  191. }
  192. template <class Clock, class Duration>
  193. bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time)
  194. {
  195. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  196. boost::this_thread::disable_interruption do_not_disturb;
  197. #endif
  198. boost::unique_lock<boost::mutex> lk(state_change);
  199. if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_shared, boost::ref(state))))
  200. {
  201. return false;
  202. }
  203. state.lock_shared();
  204. return true;
  205. }
  206. #endif
  207. void unlock_shared()
  208. {
  209. boost::unique_lock<boost::mutex> lk(state_change);
  210. state.assert_lock_shared();
  211. state.unlock_shared();
  212. if (state.no_shared())
  213. {
  214. if (state.upgrade)
  215. {
  216. // As there is a thread doing a unlock_upgrade_and_lock that is waiting for state.no_shared()
  217. // avoid other threads to lock, lock_upgrade or lock_shared, so only this thread is notified.
  218. state.upgrade=false;
  219. state.exclusive=true;
  220. //lk.unlock();
  221. upgrade_cond.notify_one();
  222. }
  223. else
  224. {
  225. state.exclusive_waiting_blocked=false;
  226. //lk.unlock();
  227. }
  228. release_waiters();
  229. }
  230. }
  231. void lock()
  232. {
  233. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  234. boost::this_thread::disable_interruption do_not_disturb;
  235. #endif
  236. boost::unique_lock<boost::mutex> lk(state_change);
  237. state.exclusive_waiting_blocked=true;
  238. exclusive_cond.wait(lk, boost::bind(&state_data::can_lock, boost::ref(state)));
  239. state.exclusive=true;
  240. }
  241. #if defined BOOST_THREAD_USES_DATETIME
  242. bool timed_lock(system_time const& timeout)
  243. {
  244. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  245. boost::this_thread::disable_interruption do_not_disturb;
  246. #endif
  247. boost::unique_lock<boost::mutex> lk(state_change);
  248. state.exclusive_waiting_blocked=true;
  249. if(!exclusive_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock, boost::ref(state))))
  250. {
  251. state.exclusive_waiting_blocked=false;
  252. release_waiters();
  253. return false;
  254. }
  255. state.exclusive=true;
  256. return true;
  257. }
  258. template<typename TimeDuration>
  259. bool timed_lock(TimeDuration const & relative_time)
  260. {
  261. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  262. boost::this_thread::disable_interruption do_not_disturb;
  263. #endif
  264. boost::unique_lock<boost::mutex> lk(state_change);
  265. state.exclusive_waiting_blocked=true;
  266. if(!exclusive_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock, boost::ref(state))))
  267. {
  268. state.exclusive_waiting_blocked=false;
  269. release_waiters();
  270. return false;
  271. }
  272. state.exclusive=true;
  273. return true;
  274. }
  275. #endif
  276. #ifdef BOOST_THREAD_USES_CHRONO
  277. template <class Rep, class Period>
  278. bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
  279. {
  280. return try_lock_until(chrono::steady_clock::now() + rel_time);
  281. }
  282. template <class Clock, class Duration>
  283. bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
  284. {
  285. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  286. boost::this_thread::disable_interruption do_not_disturb;
  287. #endif
  288. boost::unique_lock<boost::mutex> lk(state_change);
  289. state.exclusive_waiting_blocked=true;
  290. if(!exclusive_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock, boost::ref(state))))
  291. {
  292. state.exclusive_waiting_blocked=false;
  293. release_waiters();
  294. return false;
  295. }
  296. state.exclusive=true;
  297. return true;
  298. }
  299. #endif
  300. bool try_lock()
  301. {
  302. boost::unique_lock<boost::mutex> lk(state_change);
  303. if(!state.can_lock())
  304. {
  305. return false;
  306. }
  307. state.exclusive=true;
  308. return true;
  309. }
  310. void unlock()
  311. {
  312. boost::unique_lock<boost::mutex> lk(state_change);
  313. state.assert_locked();
  314. state.exclusive=false;
  315. state.exclusive_waiting_blocked=false;
  316. state.assert_free();
  317. release_waiters();
  318. }
  319. void lock_upgrade()
  320. {
  321. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  322. boost::this_thread::disable_interruption do_not_disturb;
  323. #endif
  324. boost::unique_lock<boost::mutex> lk(state_change);
  325. shared_cond.wait(lk, boost::bind(&state_data::can_lock_upgrade, boost::ref(state)));
  326. state.lock_shared();
  327. state.upgrade=true;
  328. }
  329. #if defined BOOST_THREAD_USES_DATETIME
  330. bool timed_lock_upgrade(system_time const& timeout)
  331. {
  332. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  333. boost::this_thread::disable_interruption do_not_disturb;
  334. #endif
  335. boost::unique_lock<boost::mutex> lk(state_change);
  336. if(!shared_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
  337. {
  338. return false;
  339. }
  340. state.lock_shared();
  341. state.upgrade=true;
  342. return true;
  343. }
  344. template<typename TimeDuration>
  345. bool timed_lock_upgrade(TimeDuration const & relative_time)
  346. {
  347. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  348. boost::this_thread::disable_interruption do_not_disturb;
  349. #endif
  350. boost::unique_lock<boost::mutex> lk(state_change);
  351. if(!shared_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
  352. {
  353. return false;
  354. }
  355. state.lock_shared();
  356. state.upgrade=true;
  357. return true;
  358. }
  359. #endif
  360. #ifdef BOOST_THREAD_USES_CHRONO
  361. template <class Rep, class Period>
  362. bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time)
  363. {
  364. return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
  365. }
  366. template <class Clock, class Duration>
  367. bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time)
  368. {
  369. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  370. boost::this_thread::disable_interruption do_not_disturb;
  371. #endif
  372. boost::unique_lock<boost::mutex> lk(state_change);
  373. if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
  374. {
  375. return false;
  376. }
  377. state.lock_shared();
  378. state.upgrade=true;
  379. return true;
  380. }
  381. #endif
  382. bool try_lock_upgrade()
  383. {
  384. boost::unique_lock<boost::mutex> lk(state_change);
  385. if(!state.can_lock_upgrade())
  386. {
  387. return false;
  388. }
  389. state.lock_shared();
  390. state.upgrade=true;
  391. state.assert_lock_upgraded();
  392. return true;
  393. }
  394. void unlock_upgrade()
  395. {
  396. boost::unique_lock<boost::mutex> lk(state_change);
  397. //state.upgrade=false;
  398. state.unlock_upgrade();
  399. if(state.no_shared())
  400. {
  401. state.exclusive_waiting_blocked=false;
  402. release_waiters();
  403. } else {
  404. shared_cond.notify_all();
  405. }
  406. }
  407. // Upgrade <-> Exclusive
  408. void unlock_upgrade_and_lock()
  409. {
  410. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  411. boost::this_thread::disable_interruption do_not_disturb;
  412. #endif
  413. boost::unique_lock<boost::mutex> lk(state_change);
  414. state.assert_lock_upgraded();
  415. state.unlock_shared();
  416. upgrade_cond.wait(lk, boost::bind(&state_data::no_shared, boost::ref(state)));
  417. state.upgrade=false;
  418. state.exclusive=true;
  419. state.assert_locked();
  420. }
  421. void unlock_and_lock_upgrade()
  422. {
  423. boost::unique_lock<boost::mutex> lk(state_change);
  424. state.assert_locked();
  425. state.exclusive=false;
  426. state.upgrade=true;
  427. state.lock_shared();
  428. state.exclusive_waiting_blocked=false;
  429. state.assert_lock_upgraded();
  430. release_waiters();
  431. }
  432. bool try_unlock_upgrade_and_lock()
  433. {
  434. boost::unique_lock<boost::mutex> lk(state_change);
  435. state.assert_lock_upgraded();
  436. if( !state.exclusive
  437. && !state.exclusive_waiting_blocked
  438. && state.upgrade
  439. && state.shared_count==1)
  440. {
  441. state.shared_count=0;
  442. state.exclusive=true;
  443. state.upgrade=false;
  444. state.assert_locked();
  445. return true;
  446. }
  447. return false;
  448. }
  449. #ifdef BOOST_THREAD_USES_CHRONO
  450. template <class Rep, class Period>
  451. bool
  452. try_unlock_upgrade_and_lock_for(
  453. const chrono::duration<Rep, Period>& rel_time)
  454. {
  455. return try_unlock_upgrade_and_lock_until(
  456. chrono::steady_clock::now() + rel_time);
  457. }
  458. template <class Clock, class Duration>
  459. bool
  460. try_unlock_upgrade_and_lock_until(
  461. const chrono::time_point<Clock, Duration>& abs_time)
  462. {
  463. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  464. boost::this_thread::disable_interruption do_not_disturb;
  465. #endif
  466. boost::unique_lock<boost::mutex> lk(state_change);
  467. state.assert_lock_upgraded();
  468. if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::one_shared, boost::ref(state))))
  469. {
  470. return false;
  471. }
  472. state.upgrade=false;
  473. state.exclusive=true;
  474. state.exclusive_waiting_blocked=false;
  475. state.shared_count=0;
  476. return true;
  477. }
  478. #endif
  479. // Shared <-> Exclusive
  480. void unlock_and_lock_shared()
  481. {
  482. boost::unique_lock<boost::mutex> lk(state_change);
  483. state.assert_locked();
  484. state.exclusive=false;
  485. state.lock_shared();
  486. state.exclusive_waiting_blocked=false;
  487. release_waiters();
  488. }
  489. #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
  490. bool try_unlock_shared_and_lock()
  491. {
  492. boost::unique_lock<boost::mutex> lk(state_change);
  493. state.assert_lock_shared();
  494. if( !state.exclusive
  495. && !state.exclusive_waiting_blocked
  496. && !state.upgrade
  497. && state.shared_count==1)
  498. {
  499. state.shared_count=0;
  500. state.exclusive=true;
  501. return true;
  502. }
  503. return false;
  504. }
  505. #ifdef BOOST_THREAD_USES_CHRONO
  506. template <class Rep, class Period>
  507. bool
  508. try_unlock_shared_and_lock_for(
  509. const chrono::duration<Rep, Period>& rel_time)
  510. {
  511. return try_unlock_shared_and_lock_until(
  512. chrono::steady_clock::now() + rel_time);
  513. }
  514. template <class Clock, class Duration>
  515. bool
  516. try_unlock_shared_and_lock_until(
  517. const chrono::time_point<Clock, Duration>& abs_time)
  518. {
  519. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  520. boost::this_thread::disable_interruption do_not_disturb;
  521. #endif
  522. boost::unique_lock<boost::mutex> lk(state_change);
  523. state.assert_lock_shared();
  524. if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::one_shared, boost::ref(state))))
  525. {
  526. return false;
  527. }
  528. state.upgrade=false;
  529. state.exclusive=true;
  530. state.exclusive_waiting_blocked=false;
  531. state.shared_count=0;
  532. return true;
  533. }
  534. #endif
  535. #endif
  536. // Shared <-> Upgrade
  537. void unlock_upgrade_and_lock_shared()
  538. {
  539. boost::unique_lock<boost::mutex> lk(state_change);
  540. state.assert_lock_upgraded();
  541. state.upgrade=false;
  542. state.exclusive_waiting_blocked=false;
  543. release_waiters();
  544. }
  545. #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
  546. bool try_unlock_shared_and_lock_upgrade()
  547. {
  548. boost::unique_lock<boost::mutex> lk(state_change);
  549. state.assert_lock_shared();
  550. if(state.can_lock_upgrade())
  551. {
  552. state.upgrade=true;
  553. return true;
  554. }
  555. return false;
  556. }
  557. #ifdef BOOST_THREAD_USES_CHRONO
  558. template <class Rep, class Period>
  559. bool
  560. try_unlock_shared_and_lock_upgrade_for(
  561. const chrono::duration<Rep, Period>& rel_time)
  562. {
  563. return try_unlock_shared_and_lock_upgrade_until(
  564. chrono::steady_clock::now() + rel_time);
  565. }
  566. template <class Clock, class Duration>
  567. bool
  568. try_unlock_shared_and_lock_upgrade_until(
  569. const chrono::time_point<Clock, Duration>& abs_time)
  570. {
  571. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  572. boost::this_thread::disable_interruption do_not_disturb;
  573. #endif
  574. boost::unique_lock<boost::mutex> lk(state_change);
  575. state.assert_lock_shared();
  576. if(!exclusive_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
  577. {
  578. return false;
  579. }
  580. state.upgrade=true;
  581. return true;
  582. }
  583. #endif
  584. #endif
  585. };
  586. typedef shared_mutex upgrade_mutex;
  587. }
  588. #include <boost/config/abi_suffix.hpp>
  589. #endif