intrusive_fcqueue.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. // Copyright (c) 2006-2018 Maxim Khizhinsky
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #include <cds_test/ext_gtest.h>
  6. #include <cds/intrusive/fcqueue.h>
  7. #include <vector>
  8. #include <boost/intrusive/slist.hpp>
  9. namespace {
  10. class IntrusiveFCQueue : public ::testing::Test
  11. {
  12. protected:
  13. template <typename Hook>
  14. struct base_hook_item : public Hook
  15. {
  16. int nVal;
  17. int nDisposeCount;
  18. base_hook_item()
  19. : nDisposeCount( 0 )
  20. {}
  21. };
  22. template <typename Hook>
  23. struct member_hook_item
  24. {
  25. int nVal;
  26. int nDisposeCount;
  27. Hook hMember;
  28. member_hook_item()
  29. : nDisposeCount( 0 )
  30. {}
  31. };
  32. public:
  33. struct disposer
  34. {
  35. template <typename T>
  36. void operator ()( T * p )
  37. {
  38. ++p->nDisposeCount;
  39. }
  40. };
  41. protected:
  42. template <typename Queue>
  43. void test( Queue& q )
  44. {
  45. typedef typename Queue::value_type value_type;
  46. typedef typename Queue::container_type underlying_queue_type;
  47. size_t const nSize = 100;
  48. value_type * pv;
  49. std::vector<value_type> arr;
  50. arr.resize( nSize );
  51. int total_sum = 0;
  52. for ( size_t i = 0; i < nSize; ++i ) {
  53. arr[i].nVal = static_cast<int>( i );
  54. total_sum += static_cast<int>( i );
  55. }
  56. ASSERT_TRUE( q.empty());
  57. ASSERT_EQ( q.size(), 0u );
  58. // pop from empty queue
  59. pv = q.pop();
  60. ASSERT_TRUE( pv == nullptr );
  61. ASSERT_TRUE( q.empty());
  62. ASSERT_EQ( q.size(), 0u );
  63. pv = q.dequeue();
  64. ASSERT_TRUE( pv == nullptr );
  65. ASSERT_TRUE( q.empty());
  66. ASSERT_EQ( q.size(), 0u );
  67. // push/pop test
  68. for ( size_t i = 0; i < nSize; ++i ) {
  69. if ( i & 1 )
  70. q.push( arr[i] );
  71. else
  72. q.enqueue( arr[i] );
  73. ASSERT_FALSE( q.empty());
  74. ASSERT_EQ( q.size(), i + 1 );
  75. }
  76. int sum = 0;
  77. q.apply( [&sum]( underlying_queue_type& queue )
  78. {
  79. for ( auto const& el : queue )
  80. sum += el.nVal;
  81. } );
  82. EXPECT_EQ( sum, total_sum );
  83. for ( size_t i = 0; i < nSize; ++i ) {
  84. ASSERT_FALSE( q.empty());
  85. ASSERT_EQ( q.size(), nSize - i );
  86. if ( i & 1 )
  87. pv = q.pop();
  88. else
  89. pv = q.dequeue();
  90. ASSERT_FALSE( pv == nullptr );
  91. ASSERT_EQ( pv->nVal, static_cast<int>(i));
  92. }
  93. ASSERT_TRUE( q.empty());
  94. ASSERT_EQ( q.size(), 0u );
  95. // pop() doesn't call disposer
  96. for ( size_t i = 0; i < nSize; ++i ) {
  97. ASSERT_EQ( arr[i].nDisposeCount, 0 );
  98. }
  99. // clear with disposer
  100. for ( size_t i = 0; i < nSize; ++i )
  101. q.push( arr[i] );
  102. ASSERT_FALSE( q.empty());
  103. ASSERT_EQ( q.size(), nSize );
  104. q.clear( true );
  105. ASSERT_TRUE( q.empty());
  106. ASSERT_EQ( q.size(), 0u );
  107. for ( size_t i = 0; i < nSize; ++i ) {
  108. ASSERT_EQ( arr[i].nDisposeCount, 1 );
  109. }
  110. // clear without disposer
  111. for ( size_t i = 0; i < nSize; ++i )
  112. q.push( arr[i] );
  113. q.clear();
  114. ASSERT_TRUE( q.empty());
  115. ASSERT_EQ( q.size(), 0u );
  116. for ( size_t i = 0; i < nSize; ++i ) {
  117. ASSERT_EQ( arr[i].nDisposeCount, 1 );
  118. }
  119. }
  120. };
  121. TEST_F( IntrusiveFCQueue, base )
  122. {
  123. typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type;
  124. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type >,
  125. cds::intrusive::fcqueue::make_traits<
  126. cds::intrusive::opt::disposer< disposer >
  127. >::type
  128. > queue_type;
  129. queue_type q;
  130. test( q );
  131. }
  132. TEST_F( IntrusiveFCQueue, base_empty_wait_strategy )
  133. {
  134. typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type;
  135. struct traits: public cds::intrusive::fcqueue::traits
  136. {
  137. typedef IntrusiveFCQueue::disposer disposer;
  138. typedef cds::algo::flat_combining::wait_strategy::empty wait_strategy;
  139. typedef cds::intrusive::fcqueue::stat<> stat;
  140. };
  141. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type >, traits > queue_type;
  142. queue_type q;
  143. test( q );
  144. }
  145. TEST_F( IntrusiveFCQueue, base_single_mutex_single_condvar )
  146. {
  147. typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type;
  148. struct traits: public cds::intrusive::fcqueue::traits
  149. {
  150. typedef IntrusiveFCQueue::disposer disposer;
  151. typedef cds::algo::flat_combining::wait_strategy::single_mutex_single_condvar<> wait_strategy;
  152. typedef cds::intrusive::fcqueue::stat<> stat;
  153. };
  154. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type >, traits > queue_type;
  155. queue_type q;
  156. test( q );
  157. }
  158. TEST_F( IntrusiveFCQueue, base_mutex )
  159. {
  160. typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type;
  161. struct traits : public cds::intrusive::fcqueue::traits
  162. {
  163. typedef IntrusiveFCQueue::disposer disposer;
  164. typedef std::mutex lock_type;
  165. typedef cds::intrusive::fcqueue::stat<> stat;
  166. };
  167. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type >, traits > queue_type;
  168. queue_type q;
  169. test( q );
  170. }
  171. TEST_F( IntrusiveFCQueue, base_mutex_single_mutex_multi_condvar )
  172. {
  173. typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type;
  174. struct traits: public cds::intrusive::fcqueue::traits
  175. {
  176. typedef IntrusiveFCQueue::disposer disposer;
  177. typedef std::mutex lock_type;
  178. typedef cds::intrusive::fcqueue::stat<> stat;
  179. typedef cds::algo::flat_combining::wait_strategy::single_mutex_multi_condvar<> wait_strategy;
  180. };
  181. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type >, traits > queue_type;
  182. queue_type q;
  183. test( q );
  184. }
  185. TEST_F( IntrusiveFCQueue, base_elimination )
  186. {
  187. typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type;
  188. struct traits : public
  189. cds::intrusive::fcqueue::make_traits <
  190. cds::intrusive::opt::disposer< disposer >
  191. , cds::opt::enable_elimination < true >
  192. > ::type
  193. {};
  194. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type >, traits > queue_type;
  195. queue_type q;
  196. test( q );
  197. }
  198. TEST_F( IntrusiveFCQueue, base_elimination_multi_mutex_multi_condvar )
  199. {
  200. typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type;
  201. struct traits: public
  202. cds::intrusive::fcqueue::make_traits <
  203. cds::intrusive::opt::disposer< disposer >
  204. , cds::opt::enable_elimination < true >
  205. , cds::opt::wait_strategy< cds::algo::flat_combining::wait_strategy::single_mutex_multi_condvar<>>
  206. > ::type
  207. {};
  208. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type >, traits > queue_type;
  209. queue_type q;
  210. test( q );
  211. }
  212. TEST_F( IntrusiveFCQueue, member )
  213. {
  214. typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type;
  215. typedef boost::intrusive::member_hook<value_type, boost::intrusive::list_member_hook<>, &value_type::hMember> member_option;
  216. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type, member_option >,
  217. cds::intrusive::fcqueue::make_traits<
  218. cds::intrusive::opt::disposer< disposer >
  219. >::type
  220. > queue_type;
  221. queue_type q;
  222. test( q );
  223. }
  224. TEST_F( IntrusiveFCQueue, member_mutex )
  225. {
  226. typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type;
  227. typedef boost::intrusive::member_hook<value_type, boost::intrusive::list_member_hook<>, &value_type::hMember> member_option;
  228. struct traits : public cds::intrusive::fcqueue::traits
  229. {
  230. typedef IntrusiveFCQueue::disposer disposer;
  231. typedef std::mutex lock_type;
  232. typedef cds::intrusive::fcqueue::stat<> stat;
  233. };
  234. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type, member_option >, traits > queue_type;
  235. queue_type q;
  236. test( q );
  237. }
  238. TEST_F( IntrusiveFCQueue, member_empty_wait_strategy )
  239. {
  240. typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type;
  241. typedef boost::intrusive::member_hook<value_type, boost::intrusive::list_member_hook<>, &value_type::hMember> member_option;
  242. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type, member_option >,
  243. cds::intrusive::fcqueue::make_traits<
  244. cds::intrusive::opt::disposer< disposer >
  245. , cds::opt::wait_strategy< cds::algo::flat_combining::wait_strategy::empty >
  246. >::type
  247. > queue_type;
  248. queue_type q;
  249. test( q );
  250. }
  251. TEST_F( IntrusiveFCQueue, member_single_mutex_single_condvar )
  252. {
  253. typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type;
  254. typedef boost::intrusive::member_hook<value_type, boost::intrusive::list_member_hook<>, &value_type::hMember> member_option;
  255. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type, member_option >,
  256. cds::intrusive::fcqueue::make_traits<
  257. cds::intrusive::opt::disposer< disposer >
  258. , cds::opt::wait_strategy< cds::algo::flat_combining::wait_strategy::single_mutex_single_condvar<2>>
  259. >::type
  260. > queue_type;
  261. queue_type q;
  262. test( q );
  263. }
  264. TEST_F( IntrusiveFCQueue, member_multi_mutex_multi_condvar )
  265. {
  266. typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type;
  267. typedef boost::intrusive::member_hook<value_type, boost::intrusive::list_member_hook<>, &value_type::hMember> member_option;
  268. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type, member_option >,
  269. cds::intrusive::fcqueue::make_traits<
  270. cds::intrusive::opt::disposer< disposer >
  271. , cds::opt::wait_strategy< cds::algo::flat_combining::wait_strategy::multi_mutex_multi_condvar<>>
  272. >::type
  273. > queue_type;
  274. queue_type q;
  275. test( q );
  276. }
  277. TEST_F( IntrusiveFCQueue, member_elimination )
  278. {
  279. typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type;
  280. typedef boost::intrusive::member_hook<value_type, boost::intrusive::list_member_hook<>, &value_type::hMember> member_option;
  281. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type, member_option >,
  282. cds::intrusive::fcqueue::make_traits<
  283. cds::intrusive::opt::disposer< disposer >
  284. ,cds::opt::enable_elimination< true >
  285. >::type
  286. > queue_type;
  287. queue_type q;
  288. test( q );
  289. }
  290. TEST_F( IntrusiveFCQueue, member_elimination_single_mutex_multi_condvar )
  291. {
  292. typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type;
  293. typedef boost::intrusive::member_hook<value_type, boost::intrusive::list_member_hook<>, &value_type::hMember> member_option;
  294. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type, member_option >,
  295. cds::intrusive::fcqueue::make_traits<
  296. cds::intrusive::opt::disposer< disposer >
  297. ,cds::opt::enable_elimination< true >
  298. , cds::opt::wait_strategy< cds::algo::flat_combining::wait_strategy::single_mutex_multi_condvar<2>>
  299. >::type
  300. > queue_type;
  301. queue_type q;
  302. test( q );
  303. }
  304. TEST_F( IntrusiveFCQueue, slist_base )
  305. {
  306. typedef base_hook_item< boost::intrusive::slist_base_hook<>> value_type;
  307. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::slist< value_type, boost::intrusive::cache_last< true >>,
  308. cds::intrusive::fcqueue::make_traits<
  309. cds::intrusive::opt::disposer< disposer >
  310. >::type
  311. > queue_type;
  312. queue_type q;
  313. test( q );
  314. }
  315. TEST_F( IntrusiveFCQueue, slist_base_elimination )
  316. {
  317. typedef base_hook_item< boost::intrusive::slist_base_hook<> > value_type;
  318. struct traits : public
  319. cds::intrusive::fcqueue::make_traits <
  320. cds::intrusive::opt::disposer< disposer >
  321. , cds::opt::enable_elimination < true >
  322. , cds::opt::lock_type< std::mutex >
  323. > ::type
  324. {};
  325. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::slist< value_type, boost::intrusive::cache_last< true >>, traits > queue_type;
  326. queue_type q;
  327. test( q );
  328. }
  329. TEST_F( IntrusiveFCQueue, slist_member )
  330. {
  331. typedef member_hook_item< boost::intrusive::slist_member_hook<> > value_type;
  332. typedef boost::intrusive::member_hook<value_type, boost::intrusive::slist_member_hook<>, &value_type::hMember> member_option;
  333. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::slist< value_type, member_option, boost::intrusive::cache_last< true >>,
  334. cds::intrusive::fcqueue::make_traits<
  335. cds::intrusive::opt::disposer< disposer >
  336. >::type
  337. > queue_type;
  338. queue_type q;
  339. test( q );
  340. }
  341. TEST_F( IntrusiveFCQueue, slist_member_elimination )
  342. {
  343. typedef member_hook_item< boost::intrusive::slist_member_hook<> > value_type;
  344. typedef boost::intrusive::member_hook<value_type, boost::intrusive::slist_member_hook<>, &value_type::hMember> member_option;
  345. typedef cds::intrusive::FCQueue< value_type, boost::intrusive::slist< value_type, member_option, boost::intrusive::cache_last< true >>,
  346. cds::intrusive::fcqueue::make_traits<
  347. cds::intrusive::opt::disposer< disposer >
  348. ,cds::opt::enable_elimination< true >
  349. >::type
  350. > queue_type;
  351. queue_type q;
  352. test( q );
  353. }
  354. } // namepace