test_packaged_task_dispatch.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. // (C) Copyright 2008-10 Anthony Williams
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #include <utility>
  7. #include <memory>
  8. #include <stdexcept>
  9. #include <string>
  10. #include <boost/test/unit_test.hpp>
  11. #include <boost/fiber/all.hpp>
  12. int gi = 7;
  13. struct my_exception : public std::runtime_error {
  14. my_exception() :
  15. std::runtime_error("my_exception") {
  16. }
  17. };
  18. struct A {
  19. A() = default;
  20. A( A const&) = delete;
  21. A( A &&) = default;
  22. A & operator=( A const&) = delete;
  23. A & operator=( A &&) = default;
  24. int value;
  25. };
  26. struct B {
  27. bool bset{ false };
  28. B() = default;
  29. B( bool set) :
  30. bset{ set } {
  31. gi = 3;
  32. }
  33. ~B() {
  34. if ( bset) {
  35. gi = -1;
  36. }
  37. }
  38. B( B && other) :
  39. bset{ other.bset } {
  40. other.bset = false;
  41. }
  42. B & operator=( B && other) {
  43. if ( this == & other) return * this;
  44. bset = other.bset;
  45. other.bset = false;
  46. return * this;
  47. }
  48. B( B const&) = delete;
  49. B & operator=( B const&) = delete;
  50. };
  51. void fn1( boost::fibers::promise< int > * p, int i) {
  52. boost::this_fiber::yield();
  53. p->set_value( i);
  54. }
  55. void fn2() {
  56. boost::fibers::promise< int > p;
  57. boost::fibers::future< int > f( p.get_future() );
  58. boost::this_fiber::yield();
  59. boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p, 7).detach();
  60. boost::this_fiber::yield();
  61. BOOST_CHECK( 7 == f.get() );
  62. }
  63. int fn3() {
  64. return 3;
  65. }
  66. void fn4() {
  67. }
  68. int fn5() {
  69. boost::throw_exception( my_exception() );
  70. return 3;
  71. }
  72. void fn6() {
  73. boost::throw_exception( my_exception() );
  74. }
  75. int & fn7() {
  76. return gi;
  77. }
  78. int fn8( int i) {
  79. return i;
  80. }
  81. A fn9() {
  82. A a;
  83. a.value = 3;
  84. return a;
  85. }
  86. A fn10() {
  87. boost::throw_exception( my_exception() );
  88. return A();
  89. }
  90. B fn11( bool set) {
  91. B b( set);
  92. return b;
  93. }
  94. // packaged_task
  95. void test_packaged_task_create() {
  96. // default constructed packaged_task is not valid
  97. boost::fibers::packaged_task< int() > t1;
  98. BOOST_CHECK( ! t1.valid() );
  99. // packaged_task from function
  100. boost::fibers::packaged_task< int() > t2( fn3);
  101. BOOST_CHECK( t2.valid() );
  102. }
  103. // packaged_task
  104. void test_packaged_task_create_move() {
  105. // default constructed packaged_task is not valid
  106. boost::fibers::packaged_task< A() > t1;
  107. BOOST_CHECK( ! t1.valid() );
  108. // packaged_task from function
  109. boost::fibers::packaged_task< A() > t2( fn9);
  110. BOOST_CHECK( t2.valid() );
  111. }
  112. void test_packaged_task_create_void() {
  113. // default constructed packaged_task is not valid
  114. boost::fibers::packaged_task< void() > t1;
  115. BOOST_CHECK( ! t1.valid() );
  116. // packaged_task from function
  117. boost::fibers::packaged_task< void() > t2( fn4);
  118. BOOST_CHECK( t2.valid() );
  119. }
  120. void test_packaged_task_move() {
  121. boost::fibers::packaged_task< int() > t1( fn3);
  122. BOOST_CHECK( t1.valid() );
  123. // move construction
  124. boost::fibers::packaged_task< int() > t2( std::move( t1) );
  125. BOOST_CHECK( ! t1.valid() );
  126. BOOST_CHECK( t2.valid() );
  127. // move assignment
  128. t1 = std::move( t2);
  129. BOOST_CHECK( t1.valid() );
  130. BOOST_CHECK( ! t2.valid() );
  131. }
  132. void test_packaged_task_move_move() {
  133. boost::fibers::packaged_task< A() > t1( fn9);
  134. BOOST_CHECK( t1.valid() );
  135. // move construction
  136. boost::fibers::packaged_task< A() > t2( std::move( t1) );
  137. BOOST_CHECK( ! t1.valid() );
  138. BOOST_CHECK( t2.valid() );
  139. // move assignment
  140. t1 = std::move( t2);
  141. BOOST_CHECK( t1.valid() );
  142. BOOST_CHECK( ! t2.valid() );
  143. }
  144. void test_packaged_task_move_void() {
  145. boost::fibers::packaged_task< void() > t1( fn4);
  146. BOOST_CHECK( t1.valid() );
  147. // move construction
  148. boost::fibers::packaged_task< void() > t2( std::move( t1) );
  149. BOOST_CHECK( ! t1.valid() );
  150. BOOST_CHECK( t2.valid() );
  151. // move assignment
  152. t1 = std::move( t2);
  153. BOOST_CHECK( t1.valid() );
  154. BOOST_CHECK( ! t2.valid() );
  155. }
  156. void test_packaged_task_swap() {
  157. boost::fibers::packaged_task< int() > t1( fn3);
  158. BOOST_CHECK( t1.valid() );
  159. boost::fibers::packaged_task< int() > t2;
  160. BOOST_CHECK( ! t2.valid() );
  161. // swap
  162. t1.swap( t2);
  163. BOOST_CHECK( ! t1.valid() );
  164. BOOST_CHECK( t2.valid() );
  165. }
  166. void test_packaged_task_swap_move() {
  167. boost::fibers::packaged_task< A() > t1( fn9);
  168. BOOST_CHECK( t1.valid() );
  169. boost::fibers::packaged_task< A() > t2;
  170. BOOST_CHECK( ! t2.valid() );
  171. // swap
  172. t1.swap( t2);
  173. BOOST_CHECK( ! t1.valid() );
  174. BOOST_CHECK( t2.valid() );
  175. }
  176. void test_packaged_task_swap_void() {
  177. boost::fibers::packaged_task< void() > t1( fn4);
  178. BOOST_CHECK( t1.valid() );
  179. boost::fibers::packaged_task< void() > t2;
  180. BOOST_CHECK( ! t2.valid() );
  181. // swap
  182. t1.swap( t2);
  183. BOOST_CHECK( ! t1.valid() );
  184. BOOST_CHECK( t2.valid() );
  185. }
  186. void test_packaged_task_reset() {
  187. {
  188. boost::fibers::packaged_task< int() > p( fn3);
  189. boost::fibers::future< int > f( p.get_future() );
  190. BOOST_CHECK( p.valid() );
  191. p();
  192. BOOST_CHECK( 3 == f.get() );
  193. // reset
  194. p.reset();
  195. p();
  196. f = p.get_future();
  197. BOOST_CHECK( 3 == f.get() );
  198. }
  199. {
  200. boost::fibers::packaged_task< int() > p;
  201. bool thrown = false;
  202. try {
  203. p.reset();
  204. } catch ( boost::fibers::packaged_task_uninitialized const&) {
  205. thrown = true;
  206. }
  207. BOOST_CHECK( thrown);
  208. }
  209. }
  210. void test_packaged_task_reset_destruction() {
  211. gi = 0;
  212. boost::fibers::packaged_task< B( bool) > p( fn11);
  213. BOOST_CHECK( p.valid() );
  214. BOOST_CHECK( 0 == gi);
  215. p( true);
  216. BOOST_CHECK( 3 == gi);
  217. // reset
  218. p.reset();
  219. BOOST_CHECK( -1 == gi);
  220. p( false);
  221. BOOST_CHECK( 3 == gi);
  222. // reset
  223. p.reset();
  224. BOOST_CHECK( 3 == gi);
  225. }
  226. void test_packaged_task_reset_move() {
  227. {
  228. boost::fibers::packaged_task< A() > p( fn9);
  229. boost::fibers::future< A > f( p.get_future() );
  230. BOOST_CHECK( p.valid() );
  231. p();
  232. BOOST_CHECK( 3 == f.get().value);
  233. // reset
  234. p.reset();
  235. p();
  236. f = p.get_future();
  237. BOOST_CHECK( 3 == f.get().value);
  238. }
  239. {
  240. boost::fibers::packaged_task< A() > p;
  241. bool thrown = false;
  242. try {
  243. p.reset();
  244. } catch ( boost::fibers::packaged_task_uninitialized const&) {
  245. thrown = true;
  246. }
  247. BOOST_CHECK( thrown);
  248. }
  249. }
  250. void test_packaged_task_reset_void() {
  251. {
  252. boost::fibers::packaged_task< void() > p( fn4);
  253. boost::fibers::future< void > f( p.get_future() );
  254. BOOST_CHECK( p.valid() );
  255. p();
  256. f.get();
  257. // reset
  258. p.reset();
  259. p();
  260. f = p.get_future();
  261. f.get();
  262. }
  263. {
  264. boost::fibers::packaged_task< void() > p;
  265. bool thrown = false;
  266. try {
  267. p.reset();
  268. } catch ( boost::fibers::packaged_task_uninitialized const&) {
  269. thrown = true;
  270. }
  271. BOOST_CHECK( thrown);
  272. }
  273. }
  274. void test_packaged_task_get_future() {
  275. boost::fibers::packaged_task< int() > t1( fn3);
  276. BOOST_CHECK( t1.valid() );
  277. // retrieve future
  278. boost::fibers::future< int > f1 = t1.get_future();
  279. BOOST_CHECK( f1.valid() );
  280. // retrieve future a second time
  281. bool thrown = false;
  282. try {
  283. f1 = t1.get_future();
  284. } catch ( boost::fibers::future_already_retrieved const&) {
  285. thrown = true;
  286. }
  287. BOOST_CHECK( thrown);
  288. // move construction
  289. boost::fibers::packaged_task< int() > t2( std::move( t1) );
  290. BOOST_CHECK( ! t1.valid() );
  291. BOOST_CHECK( t2.valid() );
  292. // retrieve future from uninitialized
  293. thrown = false;
  294. try {
  295. f1 = t1.get_future();
  296. } catch ( boost::fibers::packaged_task_uninitialized const&) {
  297. thrown = true;
  298. }
  299. BOOST_CHECK( thrown);
  300. }
  301. void test_packaged_task_get_future_move() {
  302. boost::fibers::packaged_task< A() > t1( fn9);
  303. BOOST_CHECK( t1.valid() );
  304. // retrieve future
  305. boost::fibers::future< A > f1 = t1.get_future();
  306. BOOST_CHECK( f1.valid() );
  307. // retrieve future a second time
  308. bool thrown = false;
  309. try {
  310. f1 = t1.get_future();
  311. } catch ( boost::fibers::future_already_retrieved const&) {
  312. thrown = true;
  313. }
  314. BOOST_CHECK( thrown);
  315. // move construction
  316. boost::fibers::packaged_task< A() > t2( std::move( t1) );
  317. BOOST_CHECK( ! t1.valid() );
  318. BOOST_CHECK( t2.valid() );
  319. // retrieve future from uninitialized
  320. thrown = false;
  321. try {
  322. f1 = t1.get_future();
  323. } catch ( boost::fibers::packaged_task_uninitialized const&) {
  324. thrown = true;
  325. }
  326. BOOST_CHECK( thrown);
  327. }
  328. void test_packaged_task_get_future_void() {
  329. boost::fibers::packaged_task< void() > t1( fn4);
  330. BOOST_CHECK( t1.valid() );
  331. // retrieve future
  332. boost::fibers::future< void > f1 = t1.get_future();
  333. BOOST_CHECK( f1.valid() );
  334. // retrieve future a second time
  335. bool thrown = false;
  336. try {
  337. f1 = t1.get_future();
  338. } catch ( boost::fibers::future_already_retrieved const&) {
  339. thrown = true;
  340. }
  341. BOOST_CHECK( thrown);
  342. // move construction
  343. boost::fibers::packaged_task< void() > t2( std::move( t1) );
  344. BOOST_CHECK( ! t1.valid() );
  345. BOOST_CHECK( t2.valid() );
  346. // retrieve future from uninitialized
  347. thrown = false;
  348. try {
  349. f1 = t1.get_future();
  350. } catch ( boost::fibers::packaged_task_uninitialized const&) {
  351. thrown = true;
  352. }
  353. BOOST_CHECK( thrown);
  354. }
  355. void test_packaged_task_exec() {
  356. // promise takes a copyable as return type
  357. boost::fibers::packaged_task< int() > t1( fn3);
  358. BOOST_CHECK( t1.valid() );
  359. boost::fibers::future< int > f1 = t1.get_future();
  360. BOOST_CHECK( f1.valid() );
  361. // exec
  362. t1();
  363. BOOST_CHECK( 3 == f1.get() );
  364. // exec a second time
  365. bool thrown = false;
  366. try {
  367. t1();
  368. } catch ( boost::fibers::promise_already_satisfied const&) {
  369. thrown = true;
  370. }
  371. BOOST_CHECK( thrown);
  372. }
  373. void test_packaged_task_exec_move() {
  374. // promise takes a copyable as return type
  375. boost::fibers::packaged_task< A() > t1( fn9);
  376. BOOST_CHECK( t1.valid() );
  377. boost::fibers::future< A > f1 = t1.get_future();
  378. BOOST_CHECK( f1.valid() );
  379. // exec
  380. t1();
  381. BOOST_CHECK( 3 == f1.get().value);
  382. // exec a second time
  383. bool thrown = false;
  384. try {
  385. t1();
  386. } catch ( boost::fibers::promise_already_satisfied const&) {
  387. thrown = true;
  388. }
  389. BOOST_CHECK( thrown);
  390. }
  391. void test_packaged_task_exec_param() {
  392. // promise takes a copyable as return type
  393. boost::fibers::packaged_task< int( int) > t1( fn8);
  394. BOOST_CHECK( t1.valid() );
  395. boost::fibers::future< int > f1 = t1.get_future();
  396. BOOST_CHECK( f1.valid() );
  397. // exec
  398. t1( 3);
  399. BOOST_CHECK( 3 == f1.get() );
  400. // exec a second time
  401. bool thrown = false;
  402. try {
  403. t1( 7);
  404. } catch ( boost::fibers::promise_already_satisfied const&) {
  405. thrown = true;
  406. }
  407. BOOST_CHECK( thrown);
  408. //TODO: packaged_task returns a moveable-only as return type
  409. }
  410. void test_packaged_task_exec_ref() {
  411. // promise takes a copyable as return type
  412. boost::fibers::packaged_task< int&() > t1( fn7);
  413. BOOST_CHECK( t1.valid() );
  414. boost::fibers::future< int& > f1 = t1.get_future();
  415. BOOST_CHECK( f1.valid() );
  416. // exec
  417. t1();
  418. int & i = f1.get();
  419. BOOST_CHECK( &gi == &i);
  420. // exec a second time
  421. bool thrown = false;
  422. try {
  423. t1();
  424. } catch ( boost::fibers::promise_already_satisfied const&) {
  425. thrown = true;
  426. }
  427. BOOST_CHECK( thrown);
  428. //TODO: packaged_task returns a moveable-only as return type
  429. }
  430. void test_packaged_task_exec_void() {
  431. // promise takes a copyable as return type
  432. boost::fibers::packaged_task< void() > t1( fn4);
  433. BOOST_CHECK( t1.valid() );
  434. boost::fibers::future< void > f1 = t1.get_future();
  435. BOOST_CHECK( f1.valid() );
  436. // set void
  437. t1();
  438. f1.get();
  439. // exec a second time
  440. bool thrown = false;
  441. try {
  442. t1();
  443. } catch ( boost::fibers::promise_already_satisfied const&) {
  444. thrown = true;
  445. }
  446. BOOST_CHECK( thrown);
  447. }
  448. void test_packaged_task_exception() {
  449. // promise takes a copyable as return type
  450. boost::fibers::packaged_task< int() > t1( fn5);
  451. BOOST_CHECK( t1.valid() );
  452. boost::fibers::future< int > f1 = t1.get_future();
  453. BOOST_CHECK( f1.valid() );
  454. // exec
  455. t1();
  456. bool thrown = false;
  457. try {
  458. f1.get();
  459. } catch ( my_exception const&) {
  460. thrown = true;
  461. }
  462. BOOST_CHECK( thrown);
  463. boost::fibers::packaged_task< int() > t2( fn5);
  464. BOOST_CHECK( t2.valid() );
  465. boost::fibers::future< int > f2 = t2.get_future();
  466. BOOST_CHECK( f2.valid() );
  467. // exec
  468. t2();
  469. BOOST_CHECK( f2.get_exception_ptr() );
  470. thrown = false;
  471. try
  472. { std::rethrow_exception( f2.get_exception_ptr() ); }
  473. catch ( my_exception const&)
  474. { thrown = true; }
  475. BOOST_CHECK( thrown);
  476. }
  477. void test_packaged_task_exception_move() {
  478. // promise takes a moveable as return type
  479. boost::fibers::packaged_task< A() > t1( fn10);
  480. BOOST_CHECK( t1.valid() );
  481. boost::fibers::future< A > f1 = t1.get_future();
  482. BOOST_CHECK( f1.valid() );
  483. // exec
  484. t1();
  485. bool thrown = false;
  486. try {
  487. f1.get();
  488. } catch ( my_exception const&) {
  489. thrown = true;
  490. }
  491. BOOST_CHECK( thrown);
  492. boost::fibers::packaged_task< A() > t2( fn10);
  493. BOOST_CHECK( t2.valid() );
  494. boost::fibers::future< A > f2 = t2.get_future();
  495. BOOST_CHECK( f2.valid() );
  496. // exec
  497. t2();
  498. BOOST_CHECK( f2.get_exception_ptr() );
  499. thrown = false;
  500. try
  501. { std::rethrow_exception( f2.get_exception_ptr() ); }
  502. catch ( my_exception const&)
  503. { thrown = true; }
  504. BOOST_CHECK( thrown);
  505. }
  506. void test_packaged_task_exception_void() {
  507. // promise takes a copyable as return type
  508. boost::fibers::packaged_task< void() > t1( fn6);
  509. BOOST_CHECK( t1.valid() );
  510. boost::fibers::future< void > f1 = t1.get_future();
  511. BOOST_CHECK( f1.valid() );
  512. // set void
  513. t1();
  514. bool thrown = false;
  515. try {
  516. f1.get();
  517. } catch ( my_exception const&) {
  518. thrown = true;
  519. }
  520. BOOST_CHECK( thrown);
  521. boost::fibers::packaged_task< void() > t2( fn6);
  522. BOOST_CHECK( t2.valid() );
  523. boost::fibers::future< void > f2 = t2.get_future();
  524. BOOST_CHECK( f2.valid() );
  525. // exec
  526. t2();
  527. BOOST_CHECK( f2.get_exception_ptr() );
  528. thrown = false;
  529. try {
  530. std::rethrow_exception( f2.get_exception_ptr() );
  531. } catch ( my_exception const&) {
  532. thrown = true;
  533. }
  534. BOOST_CHECK( thrown);
  535. }
  536. boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) {
  537. boost::unit_test_framework::test_suite* test =
  538. BOOST_TEST_SUITE("Boost.Fiber: packaged_task test suite");
  539. test->add(BOOST_TEST_CASE(test_packaged_task_create));
  540. test->add(BOOST_TEST_CASE(test_packaged_task_create_move));
  541. test->add(BOOST_TEST_CASE(test_packaged_task_create_void));
  542. test->add(BOOST_TEST_CASE(test_packaged_task_move));
  543. test->add(BOOST_TEST_CASE(test_packaged_task_move_move));
  544. test->add(BOOST_TEST_CASE(test_packaged_task_move_void));
  545. test->add(BOOST_TEST_CASE(test_packaged_task_swap));
  546. test->add(BOOST_TEST_CASE(test_packaged_task_swap_move));
  547. test->add(BOOST_TEST_CASE(test_packaged_task_swap_void));
  548. test->add(BOOST_TEST_CASE(test_packaged_task_reset));
  549. test->add(BOOST_TEST_CASE(test_packaged_task_reset_destruction));
  550. test->add(BOOST_TEST_CASE(test_packaged_task_reset_move));
  551. test->add(BOOST_TEST_CASE(test_packaged_task_reset_void));
  552. test->add(BOOST_TEST_CASE(test_packaged_task_get_future));
  553. test->add(BOOST_TEST_CASE(test_packaged_task_get_future_move));
  554. test->add(BOOST_TEST_CASE(test_packaged_task_get_future_void));
  555. test->add(BOOST_TEST_CASE(test_packaged_task_exec));
  556. test->add(BOOST_TEST_CASE(test_packaged_task_exec_move));
  557. test->add(BOOST_TEST_CASE(test_packaged_task_exec_param));
  558. test->add(BOOST_TEST_CASE(test_packaged_task_exec_ref));
  559. test->add(BOOST_TEST_CASE(test_packaged_task_exec_void));
  560. test->add(BOOST_TEST_CASE(test_packaged_task_exception));
  561. test->add(BOOST_TEST_CASE(test_packaged_task_exception_move));
  562. test->add(BOOST_TEST_CASE(test_packaged_task_exception_void));
  563. return test;
  564. }