shared_mutex_assert.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  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/static_assert.hpp>
  11. #include <boost/thread/mutex.hpp>
  12. #include <boost/thread/condition_variable.hpp>
  13. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  14. #include <boost/thread/detail/thread_interruption.hpp>
  15. #endif
  16. #ifdef BOOST_THREAD_USES_CHRONO
  17. #include <boost/chrono/system_clocks.hpp>
  18. #include <boost/chrono/ceil.hpp>
  19. #endif
  20. #include <boost/thread/detail/delete.hpp>
  21. #include <boost/assert.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 exclusive_blocked (bool blocked)
  72. {
  73. exclusive_waiting_blocked = blocked;
  74. }
  75. void lock ()
  76. {
  77. exclusive = true;
  78. }
  79. void unlock ()
  80. {
  81. exclusive = false;
  82. exclusive_waiting_blocked = false;
  83. }
  84. bool can_lock_shared () const
  85. {
  86. return ! (exclusive || exclusive_waiting_blocked);
  87. }
  88. bool is_last_shared () const
  89. {
  90. return !shared_count ;
  91. }
  92. unsigned get_shared_count () const
  93. {
  94. return shared_count ;
  95. }
  96. unsigned lock_shared ()
  97. {
  98. return ++shared_count;
  99. }
  100. void unlock_shared ()
  101. {
  102. --shared_count;
  103. }
  104. bool unlock_shared_downgrades()
  105. {
  106. if (upgrade) {
  107. upgrade=false;
  108. exclusive=true;
  109. return true;
  110. } else {
  111. exclusive_waiting_blocked=false;
  112. return false;
  113. }
  114. }
  115. void lock_upgrade ()
  116. {
  117. lock_shared ();
  118. upgrade=true;
  119. }
  120. bool can_lock_upgrade () const
  121. {
  122. return ! (exclusive || exclusive_waiting_blocked || upgrade);
  123. }
  124. void unlock_upgrade ()
  125. {
  126. upgrade=false;
  127. unlock_shared();
  128. }
  129. //private:
  130. unsigned shared_count;
  131. bool exclusive;
  132. bool upgrade;
  133. bool exclusive_waiting_blocked;
  134. };
  135. state_data state;
  136. boost::mutex state_change;
  137. boost::condition_variable shared_cond;
  138. boost::condition_variable exclusive_cond;
  139. boost::condition_variable upgrade_cond;
  140. void release_waiters()
  141. {
  142. exclusive_cond.notify_one();
  143. shared_cond.notify_all();
  144. }
  145. public:
  146. BOOST_THREAD_NO_COPYABLE(shared_mutex)
  147. shared_mutex()
  148. {
  149. }
  150. ~shared_mutex()
  151. {
  152. }
  153. void lock_shared()
  154. {
  155. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  156. boost::this_thread::disable_interruption do_not_disturb;
  157. #endif
  158. boost::unique_lock<boost::mutex> lk(state_change);
  159. while(!state.can_lock_shared())
  160. {
  161. shared_cond.wait(lk);
  162. }
  163. state.lock_shared();
  164. }
  165. bool try_lock_shared()
  166. {
  167. boost::unique_lock<boost::mutex> lk(state_change);
  168. if(!state.can_lock_shared())
  169. {
  170. return false;
  171. }
  172. else
  173. {
  174. state.lock_shared();
  175. return true;
  176. }
  177. }
  178. #if defined BOOST_THREAD_USES_DATETIME
  179. bool timed_lock_shared(system_time const& timeout)
  180. {
  181. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  182. boost::this_thread::disable_interruption do_not_disturb;
  183. #endif
  184. boost::unique_lock<boost::mutex> lk(state_change);
  185. while(!state.can_lock_shared())
  186. {
  187. if(!shared_cond.timed_wait(lk,timeout))
  188. {
  189. return false;
  190. }
  191. }
  192. state.lock_shared();
  193. return true;
  194. }
  195. template<typename TimeDuration>
  196. bool timed_lock_shared(TimeDuration const & relative_time)
  197. {
  198. return timed_lock_shared(get_system_time()+relative_time);
  199. }
  200. #endif
  201. #ifdef BOOST_THREAD_USES_CHRONO
  202. template <class Rep, class Period>
  203. bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
  204. {
  205. return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
  206. }
  207. template <class Clock, class Duration>
  208. bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time)
  209. {
  210. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  211. boost::this_thread::disable_interruption do_not_disturb;
  212. #endif
  213. boost::unique_lock<boost::mutex> lk(state_change);
  214. while(!state.can_lock_shared())
  215. {
  216. if(cv_status::timeout==shared_cond.wait_until(lk,abs_time))
  217. {
  218. return false;
  219. }
  220. }
  221. state.lock_shared();
  222. return true;
  223. }
  224. #endif
  225. void unlock_shared()
  226. {
  227. boost::unique_lock<boost::mutex> lk(state_change);
  228. state.assert_lock_shared();
  229. state.unlock_shared();
  230. if (state.get_shared_count () == 0)
  231. {
  232. if (state.unlock_shared_downgrades())
  233. {
  234. lk.unlock();
  235. upgrade_cond.notify_one();
  236. } else {
  237. lk.unlock();
  238. }
  239. release_waiters();
  240. }
  241. }
  242. void lock()
  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. while(!state.can_lock())
  249. {
  250. state.exclusive_blocked(true);
  251. exclusive_cond.wait(lk);
  252. }
  253. state.lock();
  254. }
  255. #if defined BOOST_THREAD_USES_DATETIME
  256. bool timed_lock(system_time const& timeout)
  257. {
  258. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  259. boost::this_thread::disable_interruption do_not_disturb;
  260. #endif
  261. boost::unique_lock<boost::mutex> lk(state_change);
  262. while(!state.can_lock())
  263. {
  264. state.exclusive_blocked(true);
  265. if(!exclusive_cond.timed_wait(lk,timeout))
  266. {
  267. if(!state.can_lock())
  268. {
  269. state.exclusive_blocked(false);
  270. release_waiters();
  271. return false;
  272. }
  273. break;
  274. }
  275. }
  276. state.exclusive=true;
  277. //state.lock();
  278. return true;
  279. }
  280. template<typename TimeDuration>
  281. bool timed_lock(TimeDuration const & relative_time)
  282. {
  283. return timed_lock(get_system_time()+relative_time);
  284. }
  285. #endif
  286. #ifdef BOOST_THREAD_USES_CHRONO
  287. template <class Rep, class Period>
  288. bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
  289. {
  290. return try_lock_until(chrono::steady_clock::now() + rel_time);
  291. }
  292. template <class Clock, class Duration>
  293. bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
  294. {
  295. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  296. boost::this_thread::disable_interruption do_not_disturb;
  297. #endif
  298. boost::unique_lock<boost::mutex> lk(state_change);
  299. while(!state.can_lock())
  300. {
  301. state.exclusive_blocked(true);
  302. if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time))
  303. {
  304. if(!state.can_lock())
  305. {
  306. state.exclusive_blocked(false);
  307. release_waiters();
  308. return false;
  309. }
  310. break;
  311. }
  312. }
  313. state.exclusive=true;
  314. //state.lock();
  315. return true;
  316. }
  317. #endif
  318. bool try_lock()
  319. {
  320. boost::unique_lock<boost::mutex> lk(state_change);
  321. if(!state.can_lock())
  322. {
  323. return false;
  324. }
  325. else
  326. {
  327. state.lock();
  328. return true;
  329. }
  330. }
  331. void unlock()
  332. {
  333. boost::unique_lock<boost::mutex> lk(state_change);
  334. state.assert_locked();
  335. state.unlock();
  336. state.assert_free();
  337. release_waiters();
  338. }
  339. void lock_upgrade()
  340. {
  341. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  342. boost::this_thread::disable_interruption do_not_disturb;
  343. #endif
  344. boost::unique_lock<boost::mutex> lk(state_change);
  345. while(!state.can_lock_upgrade())
  346. {
  347. shared_cond.wait(lk);
  348. }
  349. state.lock_upgrade();
  350. }
  351. #if defined BOOST_THREAD_USES_DATETIME
  352. bool timed_lock_upgrade(system_time const& timeout)
  353. {
  354. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  355. boost::this_thread::disable_interruption do_not_disturb;
  356. #endif
  357. boost::unique_lock<boost::mutex> lk(state_change);
  358. while(!state.can_lock_upgrade())
  359. {
  360. if(!shared_cond.timed_wait(lk,timeout))
  361. {
  362. if(!state.can_lock_upgrade())
  363. {
  364. return false;
  365. }
  366. break;
  367. }
  368. }
  369. state.lock_upgrade();
  370. return true;
  371. }
  372. template<typename TimeDuration>
  373. bool timed_lock_upgrade(TimeDuration const & relative_time)
  374. {
  375. return timed_lock_upgrade(get_system_time()+relative_time);
  376. }
  377. #endif
  378. #ifdef BOOST_THREAD_USES_CHRONO
  379. template <class Rep, class Period>
  380. bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time)
  381. {
  382. return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
  383. }
  384. template <class Clock, class Duration>
  385. bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time)
  386. {
  387. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  388. boost::this_thread::disable_interruption do_not_disturb;
  389. #endif
  390. boost::unique_lock<boost::mutex> lk(state_change);
  391. while(!state.can_lock_upgrade())
  392. {
  393. if(cv_status::timeout == shared_cond.wait_until(lk,abs_time))
  394. {
  395. if(!state.can_lock_upgrade())
  396. {
  397. return false;
  398. }
  399. break;
  400. }
  401. }
  402. state.lock_upgrade();
  403. return true;
  404. }
  405. #endif
  406. bool try_lock_upgrade()
  407. {
  408. boost::unique_lock<boost::mutex> lk(state_change);
  409. if(!state.can_lock_upgrade())
  410. {
  411. return false;
  412. }
  413. else
  414. {
  415. state.lock_upgrade();
  416. state.assert_lock_upgraded();
  417. return true;
  418. }
  419. }
  420. void unlock_upgrade()
  421. {
  422. boost::unique_lock<boost::mutex> lk(state_change);
  423. state.assert_lock_upgraded();
  424. state.unlock_upgrade();
  425. state.assert_lock_not_upgraded ();
  426. if(state.get_shared_count () == 0)
  427. {
  428. state.exclusive_blocked(false);
  429. lk.unlock();
  430. release_waiters();
  431. } else {
  432. lk.unlock();
  433. shared_cond.notify_all();
  434. }
  435. }
  436. // Upgrade <-> Exclusive
  437. void unlock_upgrade_and_lock()
  438. {
  439. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  440. boost::this_thread::disable_interruption do_not_disturb;
  441. #endif
  442. boost::unique_lock<boost::mutex> lk(state_change);
  443. state.assert_lock_upgraded();
  444. // assert state.get_shared_count() >=1
  445. while(
  446. //! state.exclusive_waiting_blocked // Fixme: is this needed?
  447. //&&
  448. state.get_shared_count()!=1)
  449. {
  450. upgrade_cond.wait(lk);
  451. }
  452. state.unlock_upgrade();
  453. state.lock();
  454. state.assert_locked();
  455. }
  456. void unlock_and_lock_upgrade()
  457. {
  458. boost::unique_lock<boost::mutex> lk(state_change);
  459. state.assert_locked();
  460. state.unlock();
  461. state.lock_upgrade();
  462. state.assert_lock_upgraded();
  463. release_waiters();
  464. }
  465. bool try_unlock_upgrade_and_lock()
  466. {
  467. boost::unique_lock<boost::mutex> lk(state_change);
  468. state.assert_lock_upgraded();
  469. if( //!state.exclusive // this should be removed once the assertion work
  470. ! state.exclusive_waiting_blocked // Fixme: why this is needed?
  471. //&& state.upgrade // this should be removed once the assertion work
  472. && state.get_shared_count()==1)
  473. {
  474. state.unlock_upgrade();
  475. state.lock();
  476. state.assert_locked();
  477. return true;
  478. }
  479. return false;
  480. }
  481. #ifdef BOOST_THREAD_USES_CHRONO
  482. template <class Rep, class Period>
  483. bool
  484. try_unlock_upgrade_and_lock_for(
  485. const chrono::duration<Rep, Period>& rel_time)
  486. {
  487. return try_unlock_upgrade_and_lock_until(
  488. chrono::steady_clock::now() + rel_time);
  489. }
  490. template <class Clock, class Duration>
  491. bool
  492. try_unlock_upgrade_and_lock_until(
  493. const chrono::time_point<Clock, Duration>& abs_time)
  494. {
  495. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  496. boost::this_thread::disable_interruption do_not_disturb;
  497. #endif
  498. boost::unique_lock<boost::mutex> lk(state_change);
  499. state.assert_lock_upgraded();
  500. if (//state.exclusive // this should be removed once the assertion work
  501. state.exclusive_waiting_blocked // Fixme: is this needed?
  502. //|| ! state.upgrade // this should be removed once the assertion work
  503. || state.get_shared_count() != 1)
  504. {
  505. for (;;)
  506. {
  507. //cv_status status = shared_cond.wait_until(lk,abs_time);
  508. cv_status status = upgrade_cond.wait_until(lk,abs_time);
  509. if (//!state.exclusive // this should be removed once the assertion work
  510. ! state.exclusive_waiting_blocked // Fixme: is this needed?
  511. //&& ! state.upgrade // this should be removed once the assertion work
  512. && state.get_shared_count() == 1)
  513. break;
  514. if(status == cv_status::timeout)
  515. return false;
  516. }
  517. }
  518. state.unlock_upgrade();
  519. state.lock();
  520. return true;
  521. }
  522. #endif
  523. // Shared <-> Exclusive
  524. void unlock_and_lock_shared()
  525. {
  526. boost::unique_lock<boost::mutex> lk(state_change);
  527. state.assert_locked();
  528. state.unlock();
  529. state.lock_shared();
  530. release_waiters();
  531. }
  532. #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
  533. bool try_unlock_shared_and_lock()
  534. {
  535. boost::unique_lock<boost::mutex> lk(state_change);
  536. state.assert_lock_shared();
  537. if( //!state.exclusive // this should be removed once the assertion work
  538. ! state.exclusive_waiting_blocked // Fixme: why this is needed?
  539. //&& ! state.upgrade // Fixme: why this is needed if state.get_shared_count()==1?
  540. && state.get_shared_count()==1)
  541. {
  542. state.unlock_shared();
  543. state.lock();
  544. return true;
  545. }
  546. return false;
  547. }
  548. #ifdef BOOST_THREAD_USES_CHRONO
  549. template <class Rep, class Period>
  550. bool
  551. try_unlock_shared_and_lock_for(
  552. const chrono::duration<Rep, Period>& rel_time)
  553. {
  554. return try_unlock_shared_and_lock_until(
  555. chrono::steady_clock::now() + rel_time);
  556. }
  557. template <class Clock, class Duration>
  558. bool
  559. try_unlock_shared_and_lock_until(
  560. const chrono::time_point<Clock, Duration>& abs_time)
  561. {
  562. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  563. boost::this_thread::disable_interruption do_not_disturb;
  564. #endif
  565. boost::unique_lock<boost::mutex> lk(state_change);
  566. state.assert_lock_shared();
  567. if ( // !state.exclusive // this should be removed once the assertion work
  568. state.exclusive_waiting_blocked // Fixme: is this needed?
  569. //|| state.upgrade // Fixme: why this is needed if state.get_shared_count()==1?
  570. || state.get_shared_count() != 1)
  571. {
  572. for (;;)
  573. {
  574. cv_status status = shared_cond.wait_until(lk,abs_time);
  575. if ( //! state.exclusive // this should be removed once the assertion work
  576. ! state.exclusive_waiting_blocked // Fixme: is this needed?
  577. //&& ! state.upgrade
  578. && state.get_shared_count() == 1)
  579. break;
  580. if(status == cv_status::timeout)
  581. return false;
  582. }
  583. }
  584. state.unlock_shared();
  585. state.lock();
  586. state.upgrade=false; // Is this absolutely needed?
  587. state.exclusive_waiting_blocked=false; // Is this absolutely needed?
  588. return true;
  589. }
  590. #endif
  591. #endif
  592. // Shared <-> Upgrade
  593. void unlock_upgrade_and_lock_shared()
  594. {
  595. boost::unique_lock<boost::mutex> lk(state_change);
  596. state.assert_lock_upgraded();
  597. //state.unlock_upgrade();
  598. //state.lock_shared(); // less efficient
  599. state.upgrade=false;
  600. state.exclusive_waiting_blocked=false; // Is this absolutely needed?
  601. release_waiters();
  602. }
  603. #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
  604. bool try_unlock_shared_and_lock_upgrade()
  605. {
  606. boost::unique_lock<boost::mutex> lk(state_change);
  607. state.assert_lock_shared();
  608. if( //! state.exclusive // this should be removed once the assertion work
  609. ! state.exclusive_waiting_blocked // Fixme: is this needed?
  610. && ! state.upgrade
  611. )
  612. {
  613. state.upgrade=true;
  614. return true;
  615. }
  616. return false;
  617. }
  618. #ifdef BOOST_THREAD_USES_CHRONO
  619. template <class Rep, class Period>
  620. bool
  621. try_unlock_shared_and_lock_upgrade_for(
  622. const chrono::duration<Rep, Period>& rel_time)
  623. {
  624. return try_unlock_shared_and_lock_upgrade_until(
  625. chrono::steady_clock::now() + rel_time);
  626. }
  627. template <class Clock, class Duration>
  628. bool
  629. try_unlock_shared_and_lock_upgrade_until(
  630. const chrono::time_point<Clock, Duration>& abs_time)
  631. {
  632. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  633. boost::this_thread::disable_interruption do_not_disturb;
  634. #endif
  635. boost::unique_lock<boost::mutex> lk(state_change);
  636. state.assert_lock_shared();
  637. if( //state.exclusive // this should be removed once the assertion work
  638. state.exclusive_waiting_blocked // Fixme: is this needed?
  639. || state.upgrade
  640. )
  641. {
  642. for (;;)
  643. {
  644. cv_status status = exclusive_cond.wait_until(lk,abs_time);
  645. if( //! state.exclusive // this should be removed once the assertion work
  646. ! state.exclusive_waiting_blocked // Fixme: is this needed?
  647. && ! state.upgrade
  648. )
  649. break;
  650. if(status == cv_status::timeout)
  651. return false;
  652. }
  653. }
  654. //state.unlock_shared();
  655. //state.lock_upgrade(); // less efficient
  656. state.upgrade=true;
  657. return true;
  658. }
  659. #endif
  660. #endif
  661. };
  662. typedef shared_mutex upgrade_mutex;
  663. }
  664. #include <boost/config/abi_suffix.hpp>
  665. #endif