| 1123 | // Never allocates. Thread-safe. |
| 1124 | template<typename U> |
| 1125 | bool try_dequeue(U& item) |
| 1126 | { |
| 1127 | // Instead of simply trying each producer in turn (which could cause needless contention on the first |
| 1128 | // producer), we score them heuristically. |
| 1129 | size_t nonEmptyCount = 0; |
| 1130 | ProducerBase* best = nullptr; |
| 1131 | size_t bestSize = 0; |
| 1132 | for (auto ptr = producerListTail.load(std::memory_order_acquire); nonEmptyCount < 3 && ptr != nullptr; ptr = ptr->next_prod()) { |
| 1133 | auto size = ptr->size_approx(); |
| 1134 | if (size > 0) { |
| 1135 | if (size > bestSize) { |
| 1136 | bestSize = size; |
| 1137 | best = ptr; |
| 1138 | } |
| 1139 | ++nonEmptyCount; |
| 1140 | } |
| 1141 | } |
| 1142 | |
| 1143 | // If there was at least one non-empty queue but it appears empty at the time |
| 1144 | // we try to dequeue from it, we need to make sure every queue's been tried |
| 1145 | if (nonEmptyCount > 0) { |
| 1146 | if ((details::likely)(best->dequeue(item))) { |
| 1147 | return true; |
| 1148 | } |
| 1149 | for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { |
| 1150 | if (ptr != best && ptr->dequeue(item)) { |
| 1151 | return true; |
| 1152 | } |
| 1153 | } |
| 1154 | } |
| 1155 | return false; |
| 1156 | } |
| 1157 | |
| 1158 | // Attempts to dequeue from the queue. |
| 1159 | // Returns false if all producer streams appeared empty at the time they |
nothing calls this directly
no test coverage detected