shared_mutex.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. // Copyright (C) 2012 Vicente J. Botet Escriba
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
  6. #define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
  7. #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
  8. #include <iostream>
  9. #include <boost/thread/mutex.hpp>
  10. #include <boost/thread/shared_mutex.hpp>
  11. #include <boost/thread/lock_algorithms.hpp>
  12. #include <boost/thread/thread_only.hpp>
  13. #include <vector>
  14. #if defined BOOST_THREAD_USES_CHRONO
  15. #include <boost/chrono/chrono_io.hpp>
  16. enum {reading, writing};
  17. int state = reading;
  18. #if 1
  19. boost::mutex&
  20. cout_mut()
  21. {
  22. static boost::mutex m;
  23. return m;
  24. }
  25. void
  26. print(const char* tag, unsigned count, char ch)
  27. {
  28. boost::lock_guard<boost::mutex> _(cout_mut());
  29. std::cout << tag << count << ch;
  30. }
  31. #elif 0
  32. boost::recursive_mutex&
  33. cout_mut()
  34. {
  35. static boost::recursive_mutex m;
  36. return m;
  37. }
  38. void print() {}
  39. template <class A0, class ...Args>
  40. void
  41. print(const A0& a0, const Args& ...args)
  42. {
  43. boost::lock_guard<boost::recursive_mutex> _(cout_mut());
  44. std::cout << a0;
  45. print(args...);
  46. }
  47. #else
  48. template <class A0, class A1, class A2>
  49. void
  50. print(const A0&, const A1& a1, const A2&)
  51. {
  52. assert(a1 > 10000);
  53. }
  54. #endif
  55. namespace S
  56. {
  57. boost::shared_mutex mut;
  58. void reader()
  59. {
  60. typedef boost::chrono::steady_clock Clock;
  61. unsigned count = 0;
  62. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  63. while (Clock::now() < until)
  64. {
  65. mut.lock_shared();
  66. assert(state == reading);
  67. ++count;
  68. mut.unlock_shared();
  69. }
  70. print("reader = ", count, '\n');
  71. }
  72. void writer()
  73. {
  74. typedef boost::chrono::steady_clock Clock;
  75. unsigned count = 0;
  76. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  77. while (Clock::now() < until)
  78. {
  79. mut.lock();
  80. state = writing;
  81. assert(state == writing);
  82. state = reading;
  83. ++count;
  84. mut.unlock();
  85. }
  86. print("writer = ", count, '\n');
  87. }
  88. void try_reader()
  89. {
  90. typedef boost::chrono::steady_clock Clock;
  91. unsigned count = 0;
  92. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  93. while (Clock::now() < until)
  94. {
  95. if (mut.try_lock_shared())
  96. {
  97. assert(state == reading);
  98. ++count;
  99. mut.unlock_shared();
  100. }
  101. }
  102. print("try_reader = ", count, '\n');
  103. }
  104. void try_writer()
  105. {
  106. typedef boost::chrono::steady_clock Clock;
  107. unsigned count = 0;
  108. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  109. while (Clock::now() < until)
  110. {
  111. if (mut.try_lock())
  112. {
  113. state = writing;
  114. assert(state == writing);
  115. state = reading;
  116. ++count;
  117. mut.unlock();
  118. }
  119. }
  120. print("try_writer = ", count, '\n');
  121. }
  122. void try_for_reader()
  123. {
  124. typedef boost::chrono::steady_clock Clock;
  125. unsigned count = 0;
  126. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  127. while (Clock::now() < until)
  128. {
  129. if (mut.try_lock_shared_for(boost::chrono::microseconds(5)))
  130. {
  131. assert(state == reading);
  132. ++count;
  133. mut.unlock_shared();
  134. }
  135. }
  136. print("try_for_reader = ", count, '\n');
  137. }
  138. void try_for_writer()
  139. {
  140. typedef boost::chrono::steady_clock Clock;
  141. unsigned count = 0;
  142. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  143. while (Clock::now() < until)
  144. {
  145. if (mut.try_lock_for(boost::chrono::microseconds(5)))
  146. {
  147. state = writing;
  148. assert(state == writing);
  149. state = reading;
  150. ++count;
  151. mut.unlock();
  152. }
  153. }
  154. print("try_for_writer = ", count, '\n');
  155. }
  156. void
  157. test_shared_mutex()
  158. {
  159. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  160. {
  161. boost::thread t1(reader);
  162. boost::thread t2(writer);
  163. boost::thread t3(reader);
  164. t1.join();
  165. t2.join();
  166. t3.join();
  167. }
  168. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  169. {
  170. boost::thread t1(try_reader);
  171. boost::thread t2(try_writer);
  172. boost::thread t3(try_reader);
  173. t1.join();
  174. t2.join();
  175. t3.join();
  176. }
  177. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  178. {
  179. boost::thread t1(try_for_reader);
  180. boost::thread t2(try_for_writer);
  181. boost::thread t3(try_for_reader);
  182. t1.join();
  183. t2.join();
  184. t3.join();
  185. }
  186. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  187. }
  188. }
  189. namespace U
  190. {
  191. boost::upgrade_mutex mut;
  192. void reader()
  193. {
  194. typedef boost::chrono::steady_clock Clock;
  195. unsigned count = 0;
  196. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  197. while (Clock::now() < until)
  198. {
  199. mut.lock_shared();
  200. assert(state == reading);
  201. ++count;
  202. mut.unlock_shared();
  203. }
  204. print("reader = ", count, '\n');
  205. }
  206. void writer()
  207. {
  208. typedef boost::chrono::steady_clock Clock;
  209. unsigned count = 0;
  210. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  211. while (Clock::now() < until)
  212. {
  213. mut.lock();
  214. state = writing;
  215. assert(state == writing);
  216. state = reading;
  217. ++count;
  218. mut.unlock();
  219. }
  220. print("writer = ", count, '\n');
  221. }
  222. void try_reader()
  223. {
  224. typedef boost::chrono::steady_clock Clock;
  225. unsigned count = 0;
  226. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  227. while (Clock::now() < until)
  228. {
  229. if (mut.try_lock_shared())
  230. {
  231. assert(state == reading);
  232. ++count;
  233. mut.unlock_shared();
  234. }
  235. }
  236. print("try_reader = ", count, '\n');
  237. }
  238. void try_writer()
  239. {
  240. typedef boost::chrono::steady_clock Clock;
  241. unsigned count = 0;
  242. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  243. while (Clock::now() < until)
  244. {
  245. if (mut.try_lock())
  246. {
  247. state = writing;
  248. assert(state == writing);
  249. state = reading;
  250. ++count;
  251. mut.unlock();
  252. }
  253. }
  254. print("try_writer = ", count, '\n');
  255. }
  256. void try_for_reader()
  257. {
  258. typedef boost::chrono::steady_clock Clock;
  259. unsigned count = 0;
  260. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  261. while (Clock::now() < until)
  262. {
  263. if (mut.try_lock_shared_for(boost::chrono::microseconds(5)))
  264. {
  265. assert(state == reading);
  266. ++count;
  267. mut.unlock_shared();
  268. }
  269. }
  270. print("try_for_reader = ", count, '\n');
  271. }
  272. void try_for_writer()
  273. {
  274. typedef boost::chrono::steady_clock Clock;
  275. unsigned count = 0;
  276. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  277. while (Clock::now() < until)
  278. {
  279. if (mut.try_lock_for(boost::chrono::microseconds(5)))
  280. {
  281. state = writing;
  282. assert(state == writing);
  283. state = reading;
  284. ++count;
  285. mut.unlock();
  286. }
  287. }
  288. print("try_for_writer = ", count, '\n');
  289. }
  290. void upgradable()
  291. {
  292. typedef boost::chrono::steady_clock Clock;
  293. unsigned count = 0;
  294. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  295. while (Clock::now() < until)
  296. {
  297. mut.lock_upgrade();
  298. assert(state == reading);
  299. ++count;
  300. mut.unlock_upgrade();
  301. }
  302. print("upgradable = ", count, '\n');
  303. }
  304. void try_upgradable()
  305. {
  306. typedef boost::chrono::steady_clock Clock;
  307. unsigned count = 0;
  308. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  309. while (Clock::now() < until)
  310. {
  311. if (mut.try_lock_upgrade())
  312. {
  313. assert(state == reading);
  314. ++count;
  315. mut.unlock_upgrade();
  316. }
  317. }
  318. print("try_upgradable = ", count, '\n');
  319. }
  320. void try_for_upgradable()
  321. {
  322. typedef boost::chrono::steady_clock Clock;
  323. unsigned count = 0;
  324. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  325. while (Clock::now() < until)
  326. {
  327. if (mut.try_lock_upgrade_for(boost::chrono::microseconds(5)))
  328. {
  329. assert(state == reading);
  330. ++count;
  331. mut.unlock_upgrade();
  332. }
  333. }
  334. print("try_for_upgradable = ", count, '\n');
  335. }
  336. void clockwise()
  337. {
  338. typedef boost::chrono::steady_clock Clock;
  339. unsigned count = 0;
  340. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  341. while (Clock::now() < until)
  342. {
  343. mut.lock_shared();
  344. assert(state == reading);
  345. if (mut.try_unlock_shared_and_lock())
  346. {
  347. state = writing;
  348. }
  349. else if (mut.try_unlock_shared_and_lock_upgrade())
  350. {
  351. assert(state == reading);
  352. mut.unlock_upgrade_and_lock();
  353. state = writing;
  354. }
  355. else
  356. {
  357. mut.unlock_shared();
  358. continue;
  359. }
  360. assert(state == writing);
  361. state = reading;
  362. mut.unlock_and_lock_upgrade();
  363. assert(state == reading);
  364. mut.unlock_upgrade_and_lock_shared();
  365. assert(state == reading);
  366. mut.unlock_shared();
  367. ++count;
  368. }
  369. print("clockwise = ", count, '\n');
  370. }
  371. void counter_clockwise()
  372. {
  373. typedef boost::chrono::steady_clock Clock;
  374. unsigned count = 0;
  375. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  376. while (Clock::now() < until)
  377. {
  378. mut.lock_upgrade();
  379. assert(state == reading);
  380. mut.unlock_upgrade_and_lock();
  381. assert(state == reading);
  382. state = writing;
  383. assert(state == writing);
  384. state = reading;
  385. mut.unlock_and_lock_shared();
  386. assert(state == reading);
  387. mut.unlock_shared();
  388. ++count;
  389. }
  390. print("counter_clockwise = ", count, '\n');
  391. }
  392. void try_clockwise()
  393. {
  394. typedef boost::chrono::steady_clock Clock;
  395. unsigned count = 0;
  396. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  397. while (Clock::now() < until)
  398. {
  399. if (mut.try_lock_shared())
  400. {
  401. assert(state == reading);
  402. if (mut.try_unlock_shared_and_lock())
  403. {
  404. state = writing;
  405. }
  406. else if (mut.try_unlock_shared_and_lock_upgrade())
  407. {
  408. assert(state == reading);
  409. mut.unlock_upgrade_and_lock();
  410. state = writing;
  411. }
  412. else
  413. {
  414. mut.unlock_shared();
  415. continue;
  416. }
  417. assert(state == writing);
  418. state = reading;
  419. mut.unlock_and_lock_upgrade();
  420. assert(state == reading);
  421. mut.unlock_upgrade_and_lock_shared();
  422. assert(state == reading);
  423. mut.unlock_shared();
  424. ++count;
  425. }
  426. }
  427. print("try_clockwise = ", count, '\n');
  428. }
  429. void try_for_clockwise()
  430. {
  431. typedef boost::chrono::steady_clock Clock;
  432. unsigned count = 0;
  433. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  434. while (Clock::now() < until)
  435. {
  436. if (mut.try_lock_shared_for(boost::chrono::microseconds(5)))
  437. {
  438. assert(state == reading);
  439. if (mut.try_unlock_shared_and_lock_for(boost::chrono::microseconds(5)))
  440. {
  441. state = writing;
  442. }
  443. else if (mut.try_unlock_shared_and_lock_upgrade_for(boost::chrono::microseconds(5)))
  444. {
  445. assert(state == reading);
  446. mut.unlock_upgrade_and_lock();
  447. state = writing;
  448. }
  449. else
  450. {
  451. mut.unlock_shared();
  452. continue;
  453. }
  454. assert(state == writing);
  455. state = reading;
  456. mut.unlock_and_lock_upgrade();
  457. assert(state == reading);
  458. mut.unlock_upgrade_and_lock_shared();
  459. assert(state == reading);
  460. mut.unlock_shared();
  461. ++count;
  462. }
  463. }
  464. print("try_for_clockwise = ", count, '\n');
  465. }
  466. void try_counter_clockwise()
  467. {
  468. typedef boost::chrono::steady_clock Clock;
  469. unsigned count = 0;
  470. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  471. while (Clock::now() < until)
  472. {
  473. if (mut.try_lock_upgrade())
  474. {
  475. assert(state == reading);
  476. if (mut.try_unlock_upgrade_and_lock())
  477. {
  478. assert(state == reading);
  479. state = writing;
  480. assert(state == writing);
  481. state = reading;
  482. mut.unlock_and_lock_shared();
  483. assert(state == reading);
  484. mut.unlock_shared();
  485. ++count;
  486. }
  487. else
  488. {
  489. mut.unlock_upgrade();
  490. }
  491. }
  492. }
  493. print("try_counter_clockwise = ", count, '\n');
  494. }
  495. void try_for_counter_clockwise()
  496. {
  497. typedef boost::chrono::steady_clock Clock;
  498. unsigned count = 0;
  499. Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
  500. while (Clock::now() < until)
  501. {
  502. if (mut.try_lock_upgrade_for(boost::chrono::microseconds(5)))
  503. {
  504. assert(state == reading);
  505. if (mut.try_unlock_upgrade_and_lock_for(boost::chrono::microseconds(5)))
  506. {
  507. assert(state == reading);
  508. state = writing;
  509. assert(state == writing);
  510. state = reading;
  511. mut.unlock_and_lock_shared();
  512. assert(state == reading);
  513. mut.unlock_shared();
  514. ++count;
  515. }
  516. else
  517. {
  518. mut.unlock_upgrade();
  519. }
  520. }
  521. }
  522. print("try_for_counter_clockwise = ", count, '\n');
  523. }
  524. void
  525. test_upgrade_mutex()
  526. {
  527. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  528. {
  529. boost::thread t1(reader);
  530. boost::thread t2(writer);
  531. boost::thread t3(reader);
  532. t1.join();
  533. t2.join();
  534. t3.join();
  535. }
  536. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  537. {
  538. boost::thread t1(try_reader);
  539. boost::thread t2(try_writer);
  540. boost::thread t3(try_reader);
  541. t1.join();
  542. t2.join();
  543. t3.join();
  544. }
  545. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  546. {
  547. boost::thread t1(try_for_reader);
  548. boost::thread t2(try_for_writer);
  549. boost::thread t3(try_for_reader);
  550. t1.join();
  551. t2.join();
  552. t3.join();
  553. }
  554. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  555. {
  556. boost::thread t1(reader);
  557. boost::thread t2(writer);
  558. boost::thread t3(upgradable);
  559. t1.join();
  560. t2.join();
  561. t3.join();
  562. }
  563. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  564. {
  565. boost::thread t1(reader);
  566. boost::thread t2(writer);
  567. boost::thread t3(try_upgradable);
  568. t1.join();
  569. t2.join();
  570. t3.join();
  571. }
  572. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  573. {
  574. boost::thread t1(reader);
  575. boost::thread t2(writer);
  576. boost::thread t3(try_for_upgradable);
  577. t1.join();
  578. t2.join();
  579. t3.join();
  580. }
  581. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  582. {
  583. state = reading;
  584. boost::thread t1(clockwise);
  585. boost::thread t2(counter_clockwise);
  586. boost::thread t3(clockwise);
  587. boost::thread t4(counter_clockwise);
  588. t1.join();
  589. t2.join();
  590. t3.join();
  591. t4.join();
  592. }
  593. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  594. {
  595. state = reading;
  596. boost::thread t1(try_clockwise);
  597. boost::thread t2(try_counter_clockwise);
  598. t1.join();
  599. t2.join();
  600. }
  601. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  602. // {
  603. // state = reading;
  604. // boost::thread t1(try_for_clockwise);
  605. // boost::thread t2(try_for_counter_clockwise);
  606. // t1.join();
  607. // t2.join();
  608. // }
  609. // std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  610. }
  611. }
  612. namespace Assignment
  613. {
  614. class A
  615. {
  616. typedef boost::upgrade_mutex mutex_type;
  617. typedef boost::shared_lock<mutex_type> SharedLock;
  618. typedef boost::upgrade_lock<mutex_type> UpgradeLock;
  619. typedef boost::unique_lock<mutex_type> Lock;
  620. mutable mutex_type mut_;
  621. std::vector<double> data_;
  622. public:
  623. A(const A& a)
  624. {
  625. SharedLock _(a.mut_);
  626. data_ = a.data_;
  627. }
  628. A& operator=(const A& a)
  629. {
  630. if (this != &a)
  631. {
  632. Lock this_lock(mut_, boost::defer_lock);
  633. SharedLock that_lock(a.mut_, boost::defer_lock);
  634. boost::lock(this_lock, that_lock);
  635. data_ = a.data_;
  636. }
  637. return *this;
  638. }
  639. void swap(A& a)
  640. {
  641. Lock this_lock(mut_, boost::defer_lock);
  642. Lock that_lock(a.mut_, boost::defer_lock);
  643. boost::lock(this_lock, that_lock);
  644. data_.swap(a.data_);
  645. }
  646. void average(A& a)
  647. {
  648. assert(data_.size() == a.data_.size());
  649. assert(this != &a);
  650. Lock this_lock(mut_, boost::defer_lock);
  651. UpgradeLock share_that_lock(a.mut_, boost::defer_lock);
  652. boost::lock(this_lock, share_that_lock);
  653. for (unsigned i = 0; i < data_.size(); ++i)
  654. data_[i] = (data_[i] + a.data_[i]) / 2;
  655. SharedLock share_this_lock(boost::move(this_lock));
  656. Lock that_lock(boost::move(share_that_lock));
  657. a.data_ = data_;
  658. }
  659. };
  660. } // Assignment
  661. void temp()
  662. {
  663. using namespace boost;
  664. static upgrade_mutex mut;
  665. unique_lock<upgrade_mutex> ul(mut);
  666. shared_lock<upgrade_mutex> sl;
  667. sl = BOOST_THREAD_MAKE_RV_REF(shared_lock<upgrade_mutex>(boost::move(ul)));
  668. }
  669. int main()
  670. {
  671. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  672. typedef boost::chrono::high_resolution_clock Clock;
  673. typedef boost::chrono::duration<double> sec;
  674. Clock::time_point t0 = Clock::now();
  675. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  676. S::test_shared_mutex();
  677. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  678. U::test_upgrade_mutex();
  679. std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
  680. Clock::time_point t1 = Clock::now();
  681. std::cout << sec(t1 - t0) << '\n';
  682. return 0;
  683. }
  684. #else
  685. #error "This platform doesn't support Boost.Chrono"
  686. #endif