shared_mutex.hpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. #ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
  2. #define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
  3. // (C) Copyright 2006-8 Anthony Williams
  4. // (C) Copyright 2011-2012,2017-2018 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 <cstring>
  10. #include <boost/assert.hpp>
  11. #include <boost/detail/interlocked.hpp>
  12. #include <boost/thread/win32/thread_primitives.hpp>
  13. #include <boost/static_assert.hpp>
  14. #include <limits.h>
  15. #include <boost/thread/thread_time.hpp>
  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/thread/detail/platform_time.hpp>
  22. #include <boost/config/abi_prefix.hpp>
  23. namespace boost
  24. {
  25. class shared_mutex
  26. {
  27. private:
  28. struct state_data
  29. {
  30. unsigned long shared_count:11,
  31. shared_waiting:11,
  32. exclusive:1,
  33. upgrade:1,
  34. exclusive_waiting:7,
  35. exclusive_waiting_blocked:1;
  36. friend bool operator==(state_data const& lhs,state_data const& rhs)
  37. {
  38. return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
  39. }
  40. };
  41. static state_data interlocked_compare_exchange(state_data* target, state_data new_value, state_data comparand)
  42. {
  43. BOOST_STATIC_ASSERT(sizeof(state_data) == sizeof(long));
  44. long new_val, comp;
  45. std::memcpy(&new_val, &new_value, sizeof(new_value));
  46. std::memcpy(&comp, &comparand, sizeof(comparand));
  47. long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
  48. new_val,
  49. comp);
  50. state_data result;
  51. std::memcpy(&result, &res, sizeof(result));
  52. return result;
  53. }
  54. enum
  55. {
  56. unlock_sem = 0,
  57. exclusive_sem = 1
  58. };
  59. state_data state;
  60. detail::win32::handle semaphores[2];
  61. detail::win32::handle upgrade_sem;
  62. void release_waiters(state_data old_state)
  63. {
  64. if(old_state.exclusive_waiting)
  65. {
  66. BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
  67. }
  68. if(old_state.shared_waiting || old_state.exclusive_waiting)
  69. {
  70. BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
  71. }
  72. }
  73. void release_shared_waiters(state_data old_state)
  74. {
  75. if(old_state.shared_waiting || old_state.exclusive_waiting)
  76. {
  77. BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
  78. }
  79. }
  80. public:
  81. BOOST_THREAD_NO_COPYABLE(shared_mutex)
  82. shared_mutex()
  83. {
  84. semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
  85. semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
  86. if (!semaphores[exclusive_sem])
  87. {
  88. detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
  89. boost::throw_exception(thread_resource_error());
  90. }
  91. upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
  92. if (!upgrade_sem)
  93. {
  94. detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
  95. detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX);
  96. boost::throw_exception(thread_resource_error());
  97. }
  98. state_data state_={0,0,0,0,0,0};
  99. state=state_;
  100. }
  101. ~shared_mutex()
  102. {
  103. winapi::CloseHandle(upgrade_sem);
  104. winapi::CloseHandle(semaphores[unlock_sem]);
  105. winapi::CloseHandle(semaphores[exclusive_sem]);
  106. }
  107. bool try_lock_shared()
  108. {
  109. state_data old_state=state;
  110. for(;;)
  111. {
  112. state_data new_state=old_state;
  113. if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
  114. {
  115. ++new_state.shared_count;
  116. if(!new_state.shared_count)
  117. {
  118. return false;
  119. }
  120. }
  121. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  122. if(current_state==old_state)
  123. {
  124. break;
  125. }
  126. old_state=current_state;
  127. }
  128. return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
  129. }
  130. void lock_shared()
  131. {
  132. for(;;)
  133. {
  134. state_data old_state=state;
  135. for(;;)
  136. {
  137. state_data new_state=old_state;
  138. if(new_state.exclusive || new_state.exclusive_waiting_blocked)
  139. {
  140. ++new_state.shared_waiting;
  141. if(!new_state.shared_waiting)
  142. {
  143. boost::throw_exception(boost::lock_error());
  144. }
  145. }
  146. else
  147. {
  148. ++new_state.shared_count;
  149. if(!new_state.shared_count)
  150. {
  151. boost::throw_exception(boost::lock_error());
  152. }
  153. }
  154. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  155. if(current_state==old_state)
  156. {
  157. break;
  158. }
  159. old_state=current_state;
  160. }
  161. if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
  162. {
  163. return;
  164. }
  165. BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::win32::infinite,0)==0);
  166. }
  167. }
  168. private:
  169. unsigned long getMs(detail::platform_duration const& d)
  170. {
  171. return static_cast<unsigned long>(d.getMs());
  172. }
  173. template <typename Duration>
  174. unsigned long getMs(Duration const& d)
  175. {
  176. return static_cast<unsigned long>(chrono::ceil<chrono::milliseconds>(d).count());
  177. }
  178. template <typename Clock, typename Timepoint, typename Duration>
  179. bool do_lock_shared_until(Timepoint const& t, Duration const& max)
  180. {
  181. for(;;)
  182. {
  183. state_data old_state=state;
  184. for(;;)
  185. {
  186. state_data new_state=old_state;
  187. if(new_state.exclusive || new_state.exclusive_waiting_blocked)
  188. {
  189. ++new_state.shared_waiting;
  190. if(!new_state.shared_waiting)
  191. {
  192. boost::throw_exception(boost::lock_error());
  193. }
  194. }
  195. else
  196. {
  197. ++new_state.shared_count;
  198. if(!new_state.shared_count)
  199. {
  200. boost::throw_exception(boost::lock_error());
  201. }
  202. }
  203. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  204. if(current_state==old_state)
  205. {
  206. break;
  207. }
  208. old_state=current_state;
  209. }
  210. if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
  211. {
  212. return true;
  213. }
  214. // If the clock is the system clock, it may jump while this function
  215. // is waiting. To compensate for this and time out near the correct
  216. // time, we call WaitForSingleObjectEx() in a loop with a short
  217. // timeout and recheck the time remaining each time through the loop.
  218. unsigned long res=0;
  219. for(;;)
  220. {
  221. Duration d(t - Clock::now());
  222. if(d <= Duration::zero()) // timeout occurred
  223. {
  224. res=detail::win32::timeout;
  225. break;
  226. }
  227. if(max != Duration::zero())
  228. {
  229. d = (std::min)(d, max);
  230. }
  231. res=winapi::WaitForSingleObjectEx(semaphores[unlock_sem],getMs(d),0);
  232. if(res!=detail::win32::timeout) // semaphore released
  233. {
  234. break;
  235. }
  236. }
  237. if(res==detail::win32::timeout)
  238. {
  239. for(;;)
  240. {
  241. state_data new_state=old_state;
  242. if(new_state.exclusive || new_state.exclusive_waiting_blocked)
  243. {
  244. if(new_state.shared_waiting)
  245. {
  246. --new_state.shared_waiting;
  247. }
  248. }
  249. else
  250. {
  251. ++new_state.shared_count;
  252. if(!new_state.shared_count)
  253. {
  254. return false;
  255. }
  256. }
  257. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  258. if(current_state==old_state)
  259. {
  260. break;
  261. }
  262. old_state=current_state;
  263. }
  264. if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
  265. {
  266. return true;
  267. }
  268. return false;
  269. }
  270. BOOST_ASSERT(res==0);
  271. }
  272. }
  273. public:
  274. #if defined BOOST_THREAD_USES_DATETIME
  275. template<typename TimeDuration>
  276. bool timed_lock_shared(TimeDuration const & relative_time)
  277. {
  278. const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time));
  279. // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
  280. return do_lock_shared_until<detail::mono_platform_clock>(t, detail::platform_duration::zero());
  281. }
  282. bool timed_lock_shared(boost::system_time const& wait_until)
  283. {
  284. const detail::real_platform_timepoint t(wait_until);
  285. return do_lock_shared_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
  286. }
  287. #endif
  288. #ifdef BOOST_THREAD_USES_CHRONO
  289. template <class Rep, class Period>
  290. bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
  291. {
  292. const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time);
  293. typedef typename chrono::duration<Rep, Period> Duration;
  294. typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
  295. // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
  296. return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero());
  297. }
  298. template <class Duration>
  299. bool try_lock_shared_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
  300. {
  301. typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
  302. // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
  303. return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero());
  304. }
  305. template <class Clock, class Duration>
  306. bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t)
  307. {
  308. typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
  309. return do_lock_shared_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
  310. }
  311. #endif
  312. void unlock_shared()
  313. {
  314. state_data old_state=state;
  315. for(;;)
  316. {
  317. state_data new_state=old_state;
  318. bool const last_reader=!--new_state.shared_count;
  319. if(last_reader)
  320. {
  321. if(new_state.upgrade)
  322. {
  323. new_state.upgrade=false;
  324. new_state.exclusive=true;
  325. }
  326. else
  327. {
  328. if(new_state.exclusive_waiting)
  329. {
  330. --new_state.exclusive_waiting;
  331. new_state.exclusive_waiting_blocked=false;
  332. }
  333. new_state.shared_waiting=0;
  334. }
  335. }
  336. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  337. if(current_state==old_state)
  338. {
  339. if(last_reader)
  340. {
  341. if(old_state.upgrade)
  342. {
  343. BOOST_VERIFY(winapi::ReleaseSemaphore(upgrade_sem,1,0)!=0);
  344. }
  345. else
  346. {
  347. release_waiters(old_state);
  348. }
  349. }
  350. break;
  351. }
  352. old_state=current_state;
  353. }
  354. }
  355. bool try_lock()
  356. {
  357. state_data old_state=state;
  358. for(;;)
  359. {
  360. state_data new_state=old_state;
  361. if(new_state.shared_count || new_state.exclusive)
  362. {
  363. return false;
  364. }
  365. else
  366. {
  367. new_state.exclusive=true;
  368. }
  369. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  370. if(current_state==old_state)
  371. {
  372. break;
  373. }
  374. old_state=current_state;
  375. }
  376. return true;
  377. }
  378. void lock()
  379. {
  380. for(;;)
  381. {
  382. state_data old_state=state;
  383. for(;;)
  384. {
  385. state_data new_state=old_state;
  386. if(new_state.shared_count || new_state.exclusive)
  387. {
  388. ++new_state.exclusive_waiting;
  389. if(!new_state.exclusive_waiting)
  390. {
  391. boost::throw_exception(boost::lock_error());
  392. }
  393. new_state.exclusive_waiting_blocked=true;
  394. }
  395. else
  396. {
  397. new_state.exclusive=true;
  398. }
  399. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  400. if(current_state==old_state)
  401. {
  402. break;
  403. }
  404. old_state=current_state;
  405. }
  406. if(!old_state.shared_count && !old_state.exclusive)
  407. {
  408. return;
  409. }
  410. #ifndef UNDER_CE
  411. const bool wait_all = true;
  412. #else
  413. const bool wait_all = false;
  414. #endif
  415. BOOST_VERIFY(winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::win32::infinite,0)<2);
  416. }
  417. }
  418. private:
  419. template <typename Clock, typename Timepoint, typename Duration>
  420. bool do_lock_until(Timepoint const& t, Duration const& max)
  421. {
  422. for(;;)
  423. {
  424. state_data old_state=state;
  425. for(;;)
  426. {
  427. state_data new_state=old_state;
  428. if(new_state.shared_count || new_state.exclusive)
  429. {
  430. ++new_state.exclusive_waiting;
  431. if(!new_state.exclusive_waiting)
  432. {
  433. boost::throw_exception(boost::lock_error());
  434. }
  435. new_state.exclusive_waiting_blocked=true;
  436. }
  437. else
  438. {
  439. new_state.exclusive=true;
  440. }
  441. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  442. if(current_state==old_state)
  443. {
  444. break;
  445. }
  446. old_state=current_state;
  447. }
  448. if(!old_state.shared_count && !old_state.exclusive)
  449. {
  450. return true;
  451. }
  452. // If the clock is the system clock, it may jump while this function
  453. // is waiting. To compensate for this and time out near the correct
  454. // time, we call WaitForMultipleObjectsEx() in a loop with a short
  455. // timeout and recheck the time remaining each time through the loop.
  456. unsigned long wait_res=0;
  457. for(;;)
  458. {
  459. Duration d(t - Clock::now());
  460. if(d <= Duration::zero()) // timeout occurred
  461. {
  462. wait_res=detail::win32::timeout;
  463. break;
  464. }
  465. if(max != Duration::zero())
  466. {
  467. d = (std::min)(d, max);
  468. }
  469. #ifndef UNDER_CE
  470. wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,true,getMs(d),0);
  471. #else
  472. wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,false,getMs(d),0);
  473. #endif
  474. //wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,getMs(d), 0);
  475. if(wait_res!=detail::win32::timeout) // semaphore released
  476. {
  477. break;
  478. }
  479. }
  480. if(wait_res==detail::win32::timeout)
  481. {
  482. for(;;)
  483. {
  484. bool must_notify = false;
  485. state_data new_state=old_state;
  486. if(new_state.shared_count || new_state.exclusive)
  487. {
  488. if(new_state.exclusive_waiting)
  489. {
  490. if(!--new_state.exclusive_waiting)
  491. {
  492. new_state.exclusive_waiting_blocked=false;
  493. must_notify = true;
  494. }
  495. }
  496. }
  497. else
  498. {
  499. new_state.exclusive=true;
  500. }
  501. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  502. if (must_notify)
  503. {
  504. BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
  505. }
  506. if(current_state==old_state)
  507. {
  508. break;
  509. }
  510. old_state=current_state;
  511. }
  512. if(!old_state.shared_count && !old_state.exclusive)
  513. {
  514. return true;
  515. }
  516. return false;
  517. }
  518. BOOST_ASSERT(wait_res<2);
  519. }
  520. }
  521. public:
  522. #if defined BOOST_THREAD_USES_DATETIME
  523. bool timed_lock(boost::system_time const& wait_until)
  524. {
  525. const detail::real_platform_timepoint t(wait_until);
  526. return do_lock_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
  527. }
  528. template<typename TimeDuration>
  529. bool timed_lock(TimeDuration const & relative_time)
  530. {
  531. const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time));
  532. // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
  533. return do_lock_until<detail::mono_platform_clock>(t, detail::platform_duration::zero());
  534. }
  535. #endif
  536. #ifdef BOOST_THREAD_USES_CHRONO
  537. template <class Rep, class Period>
  538. bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
  539. {
  540. const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time);
  541. typedef typename chrono::duration<Rep, Period> Duration;
  542. typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
  543. // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
  544. return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
  545. }
  546. template <class Duration>
  547. bool try_lock_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
  548. {
  549. typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
  550. // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
  551. return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
  552. }
  553. template <class Clock, class Duration>
  554. bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
  555. {
  556. typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
  557. return do_lock_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
  558. }
  559. #endif
  560. void unlock()
  561. {
  562. state_data old_state=state;
  563. for(;;)
  564. {
  565. state_data new_state=old_state;
  566. new_state.exclusive=false;
  567. if(new_state.exclusive_waiting)
  568. {
  569. --new_state.exclusive_waiting;
  570. new_state.exclusive_waiting_blocked=false;
  571. }
  572. new_state.shared_waiting=0;
  573. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  574. if(current_state==old_state)
  575. {
  576. break;
  577. }
  578. old_state=current_state;
  579. }
  580. release_waiters(old_state);
  581. }
  582. void lock_upgrade()
  583. {
  584. for(;;)
  585. {
  586. state_data old_state=state;
  587. for(;;)
  588. {
  589. state_data new_state=old_state;
  590. if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
  591. {
  592. ++new_state.shared_waiting;
  593. if(!new_state.shared_waiting)
  594. {
  595. boost::throw_exception(boost::lock_error());
  596. }
  597. }
  598. else
  599. {
  600. ++new_state.shared_count;
  601. if(!new_state.shared_count)
  602. {
  603. boost::throw_exception(boost::lock_error());
  604. }
  605. new_state.upgrade=true;
  606. }
  607. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  608. if(current_state==old_state)
  609. {
  610. break;
  611. }
  612. old_state=current_state;
  613. }
  614. if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
  615. {
  616. return;
  617. }
  618. BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],winapi::infinite,0)==0);
  619. }
  620. }
  621. bool try_lock_upgrade()
  622. {
  623. state_data old_state=state;
  624. for(;;)
  625. {
  626. state_data new_state=old_state;
  627. if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
  628. {
  629. return false;
  630. }
  631. else
  632. {
  633. ++new_state.shared_count;
  634. if(!new_state.shared_count)
  635. {
  636. return false;
  637. }
  638. new_state.upgrade=true;
  639. }
  640. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  641. if(current_state==old_state)
  642. {
  643. break;
  644. }
  645. old_state=current_state;
  646. }
  647. return true;
  648. }
  649. void unlock_upgrade()
  650. {
  651. state_data old_state=state;
  652. for(;;)
  653. {
  654. state_data new_state=old_state;
  655. new_state.upgrade=false;
  656. bool const last_reader=!--new_state.shared_count;
  657. new_state.shared_waiting=0;
  658. if(last_reader)
  659. {
  660. if(new_state.exclusive_waiting)
  661. {
  662. --new_state.exclusive_waiting;
  663. new_state.exclusive_waiting_blocked=false;
  664. }
  665. }
  666. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  667. if(current_state==old_state)
  668. {
  669. if(last_reader)
  670. {
  671. release_waiters(old_state);
  672. }
  673. else {
  674. release_shared_waiters(old_state);
  675. }
  676. // #7720
  677. //else {
  678. // release_waiters(old_state);
  679. //}
  680. break;
  681. }
  682. old_state=current_state;
  683. }
  684. }
  685. void unlock_upgrade_and_lock()
  686. {
  687. state_data old_state=state;
  688. for(;;)
  689. {
  690. state_data new_state=old_state;
  691. bool const last_reader=!--new_state.shared_count;
  692. if(last_reader)
  693. {
  694. new_state.upgrade=false;
  695. new_state.exclusive=true;
  696. }
  697. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  698. if(current_state==old_state)
  699. {
  700. if(!last_reader)
  701. {
  702. BOOST_VERIFY(winapi::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite,0)==0);
  703. }
  704. break;
  705. }
  706. old_state=current_state;
  707. }
  708. }
  709. void unlock_and_lock_upgrade()
  710. {
  711. state_data old_state=state;
  712. for(;;)
  713. {
  714. state_data new_state=old_state;
  715. new_state.exclusive=false;
  716. new_state.upgrade=true;
  717. ++new_state.shared_count;
  718. if(new_state.exclusive_waiting)
  719. {
  720. --new_state.exclusive_waiting;
  721. new_state.exclusive_waiting_blocked=false;
  722. }
  723. new_state.shared_waiting=0;
  724. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  725. if(current_state==old_state)
  726. {
  727. break;
  728. }
  729. old_state=current_state;
  730. }
  731. release_waiters(old_state);
  732. }
  733. void unlock_and_lock_shared()
  734. {
  735. state_data old_state=state;
  736. for(;;)
  737. {
  738. state_data new_state=old_state;
  739. new_state.exclusive=false;
  740. ++new_state.shared_count;
  741. if(new_state.exclusive_waiting)
  742. {
  743. --new_state.exclusive_waiting;
  744. new_state.exclusive_waiting_blocked=false;
  745. }
  746. new_state.shared_waiting=0;
  747. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  748. if(current_state==old_state)
  749. {
  750. break;
  751. }
  752. old_state=current_state;
  753. }
  754. release_waiters(old_state);
  755. }
  756. void unlock_upgrade_and_lock_shared()
  757. {
  758. state_data old_state=state;
  759. for(;;)
  760. {
  761. state_data new_state=old_state;
  762. new_state.upgrade=false;
  763. if(new_state.exclusive_waiting)
  764. {
  765. --new_state.exclusive_waiting;
  766. new_state.exclusive_waiting_blocked=false;
  767. }
  768. new_state.shared_waiting=0;
  769. state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
  770. if(current_state==old_state)
  771. {
  772. break;
  773. }
  774. old_state=current_state;
  775. }
  776. release_waiters(old_state);
  777. }
  778. };
  779. typedef shared_mutex upgrade_mutex;
  780. }
  781. #include <boost/config/abi_suffix.hpp>
  782. #endif