@@ -96,7 +96,7 @@ struct MallocTrackingTraits : public ConcurrentQueueDefaultTraits
9696 static inline void free (void * ptr) { tracking_allocator::free (ptr); }
9797};
9898
99- template <std::size_t BlockSize = ConcurrentQueueDefaultTraits::BLOCK_SIZE , std::size_t InitialIndexSize = ConcurrentQueueDefaultTraits::EXPLICIT_INITIAL_INDEX_SIZE >
99+ template <std::size_t BlockSize = ConcurrentQueueDefaultTraits::BLOCK_SIZE , std::size_t InitialIndexSize = ConcurrentQueueDefaultTraits::EXPLICIT_INITIAL_INDEX_SIZE , bool RecycleBlocks = ConcurrentQueueDefaultTraits:: RECYCLE_ALLOCATED_BLOCKS >
100100struct TestTraits : public MallocTrackingTraits
101101{
102102 typedef std::size_t size_t ;
@@ -105,6 +105,7 @@ struct TestTraits : public MallocTrackingTraits
105105 static const size_t BLOCK_SIZE = BlockSize;
106106 static const size_t EXPLICIT_INITIAL_INDEX_SIZE = InitialIndexSize;
107107 static const size_t IMPLICIT_INITIAL_INDEX_SIZE = InitialIndexSize * 2 ;
108+ static const bool RECYCLE_ALLOCATED_BLOCKS = RecycleBlocks;
108109
109110 static inline void reset () { _malloc_count () = 0 ; _free_count () = 0 ; }
110111 static inline std::atomic<int >& _malloc_count () { static std::atomic<int > c; return c; }
@@ -991,80 +992,132 @@ class ConcurrentQueueTests : public TestClass<ConcurrentQueueTests>
991992 bool block_alloc ()
992993 {
993994 typedef TestTraits<2 > Traits;
995+ typedef TestTraits<2 , 32 , true > RecycleTraits;
994996 Traits::reset ();
995997
998+ // Explicit
996999 {
9971000 ConcurrentQueue<int , Traits> q (7 );
9981001 ASSERT_OR_FAIL (q.initialBlockPoolSize == 4 );
9991002
10001003 ASSERT_OR_FAIL (Traits::malloc_count () == 1 );
10011004 ASSERT_OR_FAIL (Traits::free_count () == 0 );
10021005
1003- ProducerToken tok (q);
1006+ {
1007+ ProducerToken tok (q);
1008+ ASSERT_OR_FAIL (Traits::malloc_count () == 3 ); // one for producer, one for its block index
1009+ ASSERT_OR_FAIL (Traits::free_count () == 0 );
1010+
1011+ // Enqueue one item too many (force extra block allocation)
1012+ for (int i = 0 ; i != 9 ; ++i) {
1013+ ASSERT_OR_FAIL (q.enqueue (tok, i));
1014+ }
1015+
1016+ ASSERT_OR_FAIL (Traits::malloc_count () == 4 );
1017+ ASSERT_OR_FAIL (Traits::free_count () == 0 );
1018+
1019+ // Still room for one more...
1020+ ASSERT_OR_FAIL (q.enqueue (tok, 9 ));
1021+ ASSERT_OR_FAIL (Traits::malloc_count () == 4 );
1022+ ASSERT_OR_FAIL (Traits::free_count () == 0 );
1023+
1024+ // No more room without further allocations
1025+ ASSERT_OR_FAIL (!q.try_enqueue (tok, 10 ));
1026+ ASSERT_OR_FAIL (Traits::malloc_count () == 4 );
1027+ ASSERT_OR_FAIL (Traits::free_count () == 0 );
1028+
1029+ // Check items were enqueued properly
1030+ int item;
1031+ for (int i = 0 ; i != 10 ; ++i) {
1032+ ASSERT_OR_FAIL (q.try_dequeue_from_producer (tok, item));
1033+ ASSERT_OR_FAIL (item == i);
1034+ }
1035+
1036+ // Queue should be empty, but not freed
1037+ ASSERT_OR_FAIL (!q.try_dequeue_from_producer (tok, item));
1038+ ASSERT_OR_FAIL (Traits::free_count () == 0 );
1039+ }
1040+ // Explicit producers are recycled, so block should still be allocated
1041+ ASSERT_OR_FAIL (Traits::free_count () == 0 );
1042+ }
1043+
1044+ ASSERT_OR_FAIL (Traits::malloc_count () == 4 );
1045+ ASSERT_OR_FAIL (Traits::free_count () == 4 );
1046+
1047+ // Implicit
1048+ Traits::reset ();
1049+ {
1050+ ConcurrentQueue<int , Traits> q (7 );
1051+ ASSERT_OR_FAIL (q.initialBlockPoolSize == 4 );
1052+
1053+ ASSERT_OR_FAIL (q.enqueue (39 ));
1054+
10041055 ASSERT_OR_FAIL (Traits::malloc_count () == 3 ); // one for producer, one for its block index
10051056 ASSERT_OR_FAIL (Traits::free_count () == 0 );
10061057
10071058 // Enqueue one item too many (force extra block allocation)
1008- for (int i = 0 ; i != 9 ; ++i) {
1009- ASSERT_OR_FAIL (q.enqueue (tok, i));
1059+ for (int i = 0 ; i != 8 ; ++i) {
1060+ ASSERT_OR_FAIL (q.enqueue (i));
10101061 }
10111062
10121063 ASSERT_OR_FAIL (Traits::malloc_count () == 4 );
10131064 ASSERT_OR_FAIL (Traits::free_count () == 0 );
10141065
10151066 // Still room for one more...
1016- ASSERT_OR_FAIL (q.enqueue (tok, 9 ));
1067+ ASSERT_OR_FAIL (q.enqueue (8 ));
10171068 ASSERT_OR_FAIL (Traits::malloc_count () == 4 );
10181069 ASSERT_OR_FAIL (Traits::free_count () == 0 );
10191070
10201071 // No more room without further allocations
1021- ASSERT_OR_FAIL (!q.try_enqueue (tok, 10 ));
1072+ ASSERT_OR_FAIL (!q.try_enqueue (9 ));
10221073 ASSERT_OR_FAIL (Traits::malloc_count () == 4 );
10231074 ASSERT_OR_FAIL (Traits::free_count () == 0 );
10241075
10251076 // Check items were enqueued properly
10261077 int item;
1027- for (int i = 0 ; i != 10 ; ++i) {
1028- ASSERT_OR_FAIL (q.try_dequeue_from_producer (tok, item));
1078+ ASSERT_OR_FAIL (q.try_dequeue (item));
1079+ ASSERT_OR_FAIL (item == 39 );
1080+ for (int i = 0 ; i != 9 ; ++i) {
1081+ ASSERT_OR_FAIL (q.try_dequeue (item));
10291082 ASSERT_OR_FAIL (item == i);
10301083 }
10311084
1032- // Queue should be empty, but not freed
1033- ASSERT_OR_FAIL (!q.try_dequeue_from_producer (tok, item));
1034- ASSERT_OR_FAIL (Traits::free_count () == 0 );
1085+ // Queue should be empty, and extra block freed
1086+ ASSERT_OR_FAIL (!q.try_dequeue ( item));
1087+ ASSERT_OR_FAIL (Traits::free_count () == 1 );
10351088 }
10361089
10371090 ASSERT_OR_FAIL (Traits::malloc_count () == 4 );
10381091 ASSERT_OR_FAIL (Traits::free_count () == 4 );
10391092
10401093 // Implicit
1041- Traits ::reset ();
1094+ RecycleTraits ::reset ();
10421095 {
1043- ConcurrentQueue<int , Traits > q (7 );
1096+ ConcurrentQueue<int , RecycleTraits > q (7 );
10441097 ASSERT_OR_FAIL (q.initialBlockPoolSize == 4 );
10451098
10461099 ASSERT_OR_FAIL (q.enqueue (39 ));
10471100
1048- ASSERT_OR_FAIL (Traits ::malloc_count () == 3 ); // one for producer, one for its block index
1049- ASSERT_OR_FAIL (Traits ::free_count () == 0 );
1101+ ASSERT_OR_FAIL (RecycleTraits ::malloc_count () == 3 ); // one for producer, one for its block index
1102+ ASSERT_OR_FAIL (RecycleTraits ::free_count () == 0 );
10501103
10511104 // Enqueue one item too many (force extra block allocation)
10521105 for (int i = 0 ; i != 8 ; ++i) {
10531106 ASSERT_OR_FAIL (q.enqueue (i));
10541107 }
10551108
1056- ASSERT_OR_FAIL (Traits ::malloc_count () == 4 );
1057- ASSERT_OR_FAIL (Traits ::free_count () == 0 );
1109+ ASSERT_OR_FAIL (RecycleTraits ::malloc_count () == 4 );
1110+ ASSERT_OR_FAIL (RecycleTraits ::free_count () == 0 );
10581111
10591112 // Still room for one more...
10601113 ASSERT_OR_FAIL (q.enqueue (8 ));
1061- ASSERT_OR_FAIL (Traits ::malloc_count () == 4 );
1062- ASSERT_OR_FAIL (Traits ::free_count () == 0 );
1114+ ASSERT_OR_FAIL (RecycleTraits ::malloc_count () == 4 );
1115+ ASSERT_OR_FAIL (RecycleTraits ::free_count () == 0 );
10631116
10641117 // No more room without further allocations
10651118 ASSERT_OR_FAIL (!q.try_enqueue (9 ));
1066- ASSERT_OR_FAIL (Traits ::malloc_count () == 4 );
1067- ASSERT_OR_FAIL (Traits ::free_count () == 0 );
1119+ ASSERT_OR_FAIL (RecycleTraits ::malloc_count () == 4 );
1120+ ASSERT_OR_FAIL (RecycleTraits ::free_count () == 0 );
10681121
10691122 // Check items were enqueued properly
10701123 int item;
@@ -1075,13 +1128,12 @@ class ConcurrentQueueTests : public TestClass<ConcurrentQueueTests>
10751128 ASSERT_OR_FAIL (item == i);
10761129 }
10771130
1078- // Queue should be empty, but not freed
1131+ // Queue should be empty, but extra block not freed
10791132 ASSERT_OR_FAIL (!q.try_dequeue (item));
1080- ASSERT_OR_FAIL (Traits ::free_count () == 0 );
1133+ ASSERT_OR_FAIL (RecycleTraits ::free_count () == 0 );
10811134 }
1082-
1083- ASSERT_OR_FAIL (Traits::malloc_count () == 4 );
1084- ASSERT_OR_FAIL (Traits::free_count () == 4 );
1135+ ASSERT_OR_FAIL (RecycleTraits::malloc_count () == 4 );
1136+ ASSERT_OR_FAIL (RecycleTraits::free_count () == 4 );
10851137
10861138 // Super-aligned
10871139 Traits::reset ();
@@ -1125,9 +1177,9 @@ class ConcurrentQueueTests : public TestClass<ConcurrentQueueTests>
11251177 ASSERT_OR_FAIL (VeryAligned::errors == 0 );
11261178 }
11271179
1128- // Queue should be empty, but not freed
1180+ // Queue should be empty, and extra block freed
11291181 ASSERT_OR_FAIL (!q.try_dequeue (item));
1130- ASSERT_OR_FAIL (Traits::free_count () == 0 );
1182+ ASSERT_OR_FAIL (Traits::free_count () == 1 );
11311183 ASSERT_OR_FAIL (VeryAligned::errors == 0 );
11321184 }
11331185
0 commit comments