test_unbuffered_channel_dispatch.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. // Copyright Oliver Kowalke 2013.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #include <chrono>
  6. #include <sstream>
  7. #include <string>
  8. #include <vector>
  9. #include <boost/assert.hpp>
  10. #include <boost/test/unit_test.hpp>
  11. #include <boost/fiber/all.hpp>
  12. struct moveable {
  13. bool state;
  14. int value;
  15. moveable() :
  16. state( false),
  17. value( -1) {
  18. }
  19. moveable( int v) :
  20. state( true),
  21. value( v) {
  22. }
  23. moveable( moveable && other) :
  24. state( other.state),
  25. value( other.value) {
  26. other.state = false;
  27. other.value = -1;
  28. }
  29. moveable & operator=( moveable && other) {
  30. if ( this == & other) return * this;
  31. state = other.state;
  32. other.state = false;
  33. value = other.value;
  34. other.value = -1;
  35. return * this;
  36. }
  37. };
  38. void test_push() {
  39. boost::fibers::unbuffered_channel< int > c;
  40. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c](){
  41. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) );
  42. });
  43. int value = 0;
  44. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) );
  45. BOOST_CHECK_EQUAL( 1, value);
  46. f.join();
  47. }
  48. void test_push_closed() {
  49. boost::fibers::unbuffered_channel< int > c;
  50. c.close();
  51. BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push( 1) );
  52. }
  53. void test_push_wait_for() {
  54. boost::fibers::unbuffered_channel< int > c;
  55. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c](){
  56. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_for( 1, std::chrono::seconds( 1) ) );
  57. });
  58. int value = 0;
  59. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) );
  60. BOOST_CHECK_EQUAL( 1, value);
  61. f.join();
  62. }
  63. void test_push_wait_for_closed() {
  64. boost::fibers::unbuffered_channel< int > c;
  65. c.close();
  66. BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push_wait_for( 1, std::chrono::seconds( 1) ) );
  67. }
  68. void test_push_wait_for_timeout() {
  69. boost::fibers::unbuffered_channel< int > c;
  70. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c](){
  71. int value = 0;
  72. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) );
  73. BOOST_CHECK_EQUAL( 1, value);
  74. });
  75. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_for( 1, std::chrono::seconds( 1) ) );
  76. BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.push_wait_for( 1, std::chrono::seconds( 1) ) );
  77. f.join();
  78. }
  79. void test_push_wait_until() {
  80. boost::fibers::unbuffered_channel< int > c;
  81. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c](){
  82. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_until( 1,
  83. std::chrono::system_clock::now() + std::chrono::seconds( 1) ) );
  84. });
  85. int value = 0;
  86. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) );
  87. BOOST_CHECK_EQUAL( 1, value);
  88. f.join();
  89. }
  90. void test_push_wait_until_closed() {
  91. boost::fibers::unbuffered_channel< int > c;
  92. c.close();
  93. BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push_wait_until( 1,
  94. std::chrono::system_clock::now() + std::chrono::seconds( 1) ) );
  95. }
  96. void test_push_wait_until_timeout() {
  97. boost::fibers::unbuffered_channel< int > c;
  98. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c](){
  99. int value = 0;
  100. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) );
  101. BOOST_CHECK_EQUAL( 1, value);
  102. });
  103. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_until( 1,
  104. std::chrono::system_clock::now() + std::chrono::seconds( 1) ) );
  105. BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.push_wait_until( 1,
  106. std::chrono::system_clock::now() + std::chrono::seconds( 1) ) );
  107. f.join();
  108. }
  109. void test_pop() {
  110. boost::fibers::unbuffered_channel< int > c;
  111. int v1 = 2, v2 = 0;
  112. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&v1,&c](){
  113. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) );
  114. });
  115. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) );
  116. BOOST_CHECK_EQUAL( v1, v2);
  117. f.join();
  118. }
  119. void test_pop_closed() {
  120. boost::fibers::unbuffered_channel< int > c;
  121. int v1 = 2, v2 = 0;
  122. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&v1,&c](){
  123. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) );
  124. c.close();
  125. });
  126. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) );
  127. BOOST_CHECK_EQUAL( v1, v2);
  128. BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop( v2) );
  129. f.join();
  130. }
  131. void test_pop_success() {
  132. boost::fibers::unbuffered_channel< int > c;
  133. int v1 = 2, v2 = 0;
  134. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v2](){
  135. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) );
  136. });
  137. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) );
  138. f.join();
  139. BOOST_CHECK_EQUAL( v1, v2);
  140. }
  141. void test_value_pop() {
  142. boost::fibers::unbuffered_channel< int > c;
  143. int v1 = 2, v2 = 0;
  144. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v1](){
  145. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) );
  146. });
  147. v2 = c.value_pop();
  148. f.join();
  149. BOOST_CHECK_EQUAL( v1, v2);
  150. }
  151. void test_value_pop_closed() {
  152. boost::fibers::unbuffered_channel< int > c;
  153. int v1 = 2;
  154. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v1](){
  155. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) );
  156. c.close();
  157. });
  158. int v2 = c.value_pop();
  159. BOOST_CHECK_EQUAL( v1, v2);
  160. f.join();
  161. bool thrown = false;
  162. try {
  163. c.value_pop();
  164. } catch ( boost::fibers::fiber_error const&) {
  165. thrown = true;
  166. }
  167. BOOST_CHECK( thrown);
  168. }
  169. void test_value_pop_success() {
  170. boost::fibers::unbuffered_channel< int > c;
  171. int v1 = 2, v2 = 0;
  172. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v2](){
  173. v2 = c.value_pop();
  174. });
  175. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) );
  176. f.join();
  177. BOOST_CHECK_EQUAL( v1, v2);
  178. }
  179. void test_pop_wait_for() {
  180. boost::fibers::unbuffered_channel< int > c;
  181. int v1 = 2, v2 = 0;
  182. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v1](){
  183. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) );
  184. });
  185. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) );
  186. f.join();
  187. BOOST_CHECK_EQUAL( v1, v2);
  188. }
  189. void test_pop_wait_for_closed() {
  190. boost::fibers::unbuffered_channel< int > c;
  191. int v1 = 2, v2 = 0;
  192. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v1](){
  193. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) );
  194. c.close();
  195. });
  196. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) );
  197. BOOST_CHECK_EQUAL( v1, v2);
  198. BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop_wait_for( v2, std::chrono::seconds( 1) ) );
  199. f.join();
  200. }
  201. void test_pop_wait_for_success() {
  202. boost::fibers::unbuffered_channel< int > c;
  203. int v1 = 2, v2 = 0;
  204. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v2](){
  205. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) );
  206. });
  207. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) );
  208. f.join();
  209. BOOST_CHECK_EQUAL( v1, v2);
  210. }
  211. void test_pop_wait_for_timeout() {
  212. boost::fibers::unbuffered_channel< int > c;
  213. int v = 0;
  214. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v](){
  215. BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.pop_wait_for( v, std::chrono::seconds( 1) ) );
  216. });
  217. f.join();
  218. }
  219. void test_pop_wait_until() {
  220. boost::fibers::unbuffered_channel< int > c;
  221. int v1 = 2, v2 = 0;
  222. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v1](){
  223. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) );
  224. });
  225. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2,
  226. std::chrono::system_clock::now() + std::chrono::seconds( 1) ) );
  227. BOOST_CHECK_EQUAL( v1, v2);
  228. f.join();
  229. }
  230. void test_pop_wait_until_closed() {
  231. boost::fibers::unbuffered_channel< int > c;
  232. int v1 = 2, v2 = 0;
  233. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v1](){
  234. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) );
  235. c.close();
  236. });
  237. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2,
  238. std::chrono::system_clock::now() + std::chrono::seconds( 1) ) );
  239. BOOST_CHECK_EQUAL( v1, v2);
  240. BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop_wait_until( v2,
  241. std::chrono::system_clock::now() + std::chrono::seconds( 1) ) );
  242. f.join();
  243. }
  244. void test_pop_wait_until_success() {
  245. boost::fibers::unbuffered_channel< int > c;
  246. int v1 = 2, v2 = 0;
  247. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v2](){
  248. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2,
  249. std::chrono::system_clock::now() + std::chrono::seconds( 1) ) );
  250. });
  251. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) );
  252. f.join();
  253. BOOST_CHECK_EQUAL( v1, v2);
  254. }
  255. void test_pop_wait_until_timeout() {
  256. boost::fibers::unbuffered_channel< int > c;
  257. int v = 0;
  258. BOOST_CHECK(
  259. boost::fibers::channel_op_status::timeout == c.pop_wait_until( v,
  260. std::chrono::system_clock::now() + std::chrono::seconds( 1) ) );
  261. }
  262. void test_wm_1() {
  263. boost::fibers::unbuffered_channel< int > c;
  264. std::vector< boost::fibers::fiber::id > ids;
  265. boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&c,&ids](){
  266. ids.push_back( boost::this_fiber::get_id() );
  267. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) );
  268. ids.push_back( boost::this_fiber::get_id() );
  269. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 2) );
  270. ids.push_back( boost::this_fiber::get_id() );
  271. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 3) );
  272. ids.push_back( boost::this_fiber::get_id() );
  273. // would be blocked because channel is full
  274. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 4) );
  275. ids.push_back( boost::this_fiber::get_id() );
  276. // would be blocked because channel is full
  277. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 5) );
  278. ids.push_back( boost::this_fiber::get_id() );
  279. });
  280. boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&c,&ids](){
  281. ids.push_back( boost::this_fiber::get_id() );
  282. BOOST_CHECK_EQUAL( 1, c.value_pop() );
  283. // let other fiber run
  284. boost::this_fiber::yield();
  285. ids.push_back( boost::this_fiber::get_id() );
  286. BOOST_CHECK_EQUAL( 2, c.value_pop() );
  287. ids.push_back( boost::this_fiber::get_id() );
  288. BOOST_CHECK_EQUAL( 3, c.value_pop() );
  289. ids.push_back( boost::this_fiber::get_id() );
  290. BOOST_CHECK_EQUAL( 4, c.value_pop() );
  291. ids.push_back( boost::this_fiber::get_id() );
  292. // would block because channel is empty
  293. BOOST_CHECK_EQUAL( 5, c.value_pop() );
  294. ids.push_back( boost::this_fiber::get_id() );
  295. });
  296. boost::fibers::fiber::id id1 = f1.get_id();
  297. boost::fibers::fiber::id id2 = f2.get_id();
  298. f1.join();
  299. f2.join();
  300. BOOST_CHECK_EQUAL( 12u, ids.size() );
  301. BOOST_CHECK_EQUAL( id1, ids[0]);
  302. BOOST_CHECK_EQUAL( id2, ids[1]);
  303. BOOST_CHECK_EQUAL( id1, ids[2]);
  304. BOOST_CHECK_EQUAL( id2, ids[3]);
  305. BOOST_CHECK_EQUAL( id2, ids[4]);
  306. BOOST_CHECK_EQUAL( id1, ids[5]);
  307. BOOST_CHECK_EQUAL( id2, ids[6]);
  308. BOOST_CHECK_EQUAL( id1, ids[7]);
  309. BOOST_CHECK_EQUAL( id2, ids[8]);
  310. BOOST_CHECK_EQUAL( id1, ids[9]);
  311. BOOST_CHECK_EQUAL( id2, ids[10]);
  312. BOOST_CHECK_EQUAL( id1, ids[11]);
  313. }
  314. void test_moveable() {
  315. boost::fibers::unbuffered_channel< moveable > c;
  316. boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c]{
  317. moveable m1( 3);
  318. BOOST_CHECK( m1.state);
  319. BOOST_CHECK_EQUAL( 3, m1.value);
  320. BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( std::move( m1) ) );
  321. });
  322. moveable m2;
  323. BOOST_CHECK( ! m2.state);
  324. BOOST_CHECK_EQUAL( -1, m2.value);
  325. BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( m2) );
  326. BOOST_CHECK( m2.state);
  327. BOOST_CHECK_EQUAL( 3, m2.value);
  328. f.join();
  329. }
  330. void test_rangefor() {
  331. boost::fibers::unbuffered_channel< int > chan;
  332. std::vector< int > vec;
  333. boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&chan]{
  334. chan.push( 1);
  335. chan.push( 1);
  336. chan.push( 2);
  337. chan.push( 3);
  338. chan.push( 5);
  339. chan.push( 8);
  340. chan.push( 12);
  341. chan.close();
  342. });
  343. boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&vec,&chan]{
  344. for ( int value : chan) {
  345. vec.push_back( value);
  346. }
  347. });
  348. f1.join();
  349. f2.join();
  350. BOOST_CHECK_EQUAL( 1, vec[0]);
  351. BOOST_CHECK_EQUAL( 1, vec[1]);
  352. BOOST_CHECK_EQUAL( 2, vec[2]);
  353. BOOST_CHECK_EQUAL( 3, vec[3]);
  354. BOOST_CHECK_EQUAL( 5, vec[4]);
  355. BOOST_CHECK_EQUAL( 8, vec[5]);
  356. BOOST_CHECK_EQUAL( 12, vec[6]);
  357. }
  358. void test_issue_181() {
  359. boost::fibers::unbuffered_channel< int > chan;
  360. boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&chan]() {
  361. auto state = chan.push( 1);
  362. BOOST_CHECK( boost::fibers::channel_op_status::closed == state);
  363. });
  364. boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&chan]() {
  365. boost::this_fiber::sleep_for( std::chrono::milliseconds( 100) );
  366. chan.close();
  367. });
  368. f2.join();
  369. f1.join();
  370. }
  371. boost::unit_test::test_suite * init_unit_test_suite( int, char* []) {
  372. boost::unit_test::test_suite * test =
  373. BOOST_TEST_SUITE("Boost.Fiber: unbuffered_channel test suite");
  374. test->add( BOOST_TEST_CASE( & test_push) );
  375. test->add( BOOST_TEST_CASE( & test_push_closed) );
  376. test->add( BOOST_TEST_CASE( & test_push_wait_for) );
  377. test->add( BOOST_TEST_CASE( & test_push_wait_for_closed) );
  378. test->add( BOOST_TEST_CASE( & test_push_wait_for_timeout) );
  379. test->add( BOOST_TEST_CASE( & test_push_wait_until) );
  380. test->add( BOOST_TEST_CASE( & test_push_wait_until_closed) );
  381. test->add( BOOST_TEST_CASE( & test_push_wait_until_timeout) );
  382. test->add( BOOST_TEST_CASE( & test_pop) );
  383. test->add( BOOST_TEST_CASE( & test_pop_closed) );
  384. test->add( BOOST_TEST_CASE( & test_pop_success) );
  385. test->add( BOOST_TEST_CASE( & test_value_pop) );
  386. test->add( BOOST_TEST_CASE( & test_value_pop_closed) );
  387. test->add( BOOST_TEST_CASE( & test_value_pop_success) );
  388. test->add( BOOST_TEST_CASE( & test_pop_wait_for) );
  389. test->add( BOOST_TEST_CASE( & test_pop_wait_for_closed) );
  390. test->add( BOOST_TEST_CASE( & test_pop_wait_for_success) );
  391. test->add( BOOST_TEST_CASE( & test_pop_wait_for_timeout) );
  392. test->add( BOOST_TEST_CASE( & test_pop_wait_until) );
  393. test->add( BOOST_TEST_CASE( & test_pop_wait_until_closed) );
  394. test->add( BOOST_TEST_CASE( & test_pop_wait_until_success) );
  395. test->add( BOOST_TEST_CASE( & test_pop_wait_until_timeout) );
  396. test->add( BOOST_TEST_CASE( & test_wm_1) );
  397. test->add( BOOST_TEST_CASE( & test_moveable) );
  398. test->add( BOOST_TEST_CASE( & test_rangefor) );
  399. test->add( BOOST_TEST_CASE( & test_issue_181) );
  400. return test;
  401. }