10#ifndef EIGEN_CXX11_THREADPOOL_RUNQUEUE_H
11#define EIGEN_CXX11_THREADPOOL_RUNQUEUE_H
14#include "./InternalHeaderCheck.h"
40template <
typename Work,
unsigned kSize>
43 RunQueue() : front_(0), back_(0) {
45 eigen_plain_assert((kSize & (kSize - 1)) == 0);
46 eigen_plain_assert(kSize > 2);
47 eigen_plain_assert(kSize <= (64 << 10));
48 for (
unsigned i = 0; i < kSize; i++) array_[i].state.store(kEmpty, std::memory_order_relaxed);
51 ~RunQueue() { eigen_plain_assert(Size() == 0); }
55 Work PushFront(Work w) {
56 unsigned front = front_.load(std::memory_order_relaxed);
57 Elem* e = &array_[front & kMask];
58 uint8_t s = e->state.load(std::memory_order_relaxed);
59 if (s != kEmpty || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire))
return w;
60 front_.store(front + 1 + (kSize << 1), std::memory_order_relaxed);
62 e->state.store(kReady, std::memory_order_release);
69 unsigned front = front_.load(std::memory_order_relaxed);
70 Elem* e = &array_[(front - 1) & kMask];
71 uint8_t s = e->state.load(std::memory_order_relaxed);
72 if (s != kReady || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire))
return Work();
73 Work w = std::move(e->w);
74 e->state.store(kEmpty, std::memory_order_release);
75 front = ((front - 1) & kMask2) | (front & ~kMask2);
76 front_.store(front, std::memory_order_relaxed);
82 Work PushBack(Work w) {
83 EIGEN_MUTEX_LOCK lock(mutex_);
84 unsigned back = back_.load(std::memory_order_relaxed);
85 Elem* e = &array_[(back - 1) & kMask];
86 uint8_t s = e->state.load(std::memory_order_relaxed);
87 if (s != kEmpty || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire))
return w;
88 back = ((back - 1) & kMask2) | (back & ~kMask2);
89 back_.store(back, std::memory_order_relaxed);
91 e->state.store(kReady, std::memory_order_release);
97 if (Empty())
return Work();
98 EIGEN_MUTEX_LOCK lock(mutex_);
99 unsigned back = back_.load(std::memory_order_relaxed);
100 Elem* e = &array_[back & kMask];
101 uint8_t s = e->state.load(std::memory_order_relaxed);
102 if (s != kReady || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire))
return Work();
103 Work w = std::move(e->w);
104 e->state.store(kEmpty, std::memory_order_release);
105 back_.store(back + 1 + (kSize << 1), std::memory_order_relaxed);
111 unsigned PopBackHalf(std::vector<Work>* result) {
112 if (Empty())
return 0;
113 EIGEN_MUTEX_LOCK lock(mutex_);
114 unsigned back = back_.load(std::memory_order_relaxed);
115 unsigned size = Size();
117 if (size > 1) mid = back + (size - 1) / 2;
120 for (;
static_cast<int>(mid - back) >= 0; mid--) {
121 Elem* e = &array_[mid & kMask];
122 uint8_t s = e->state.load(std::memory_order_relaxed);
124 if (s != kReady || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire))
continue;
129 eigen_plain_assert(s == kReady);
131 result->push_back(std::move(e->w));
132 e->state.store(kEmpty, std::memory_order_release);
135 if (n != 0) back_.store(start + 1 + (kSize << 1), std::memory_order_relaxed);
141 unsigned Size()
const {
return SizeOrNotEmpty<true>(); }
145 bool Empty()
const {
return SizeOrNotEmpty<false>() == 0; }
155 static const unsigned kMask = kSize - 1;
156 static const unsigned kMask2 = (kSize << 1) - 1;
158 std::atomic<uint8_t> state;
174 std::atomic<unsigned> front_;
175 std::atomic<unsigned> back_;
181 template <
bool NeedSizeEstimate>
182 unsigned SizeOrNotEmpty()
const {
185 unsigned front = front_.load(std::memory_order_acquire);
188 unsigned back = back_.load(std::memory_order_acquire);
189 unsigned front1 = front_.load(std::memory_order_relaxed);
190 if (front != front1) {
192 std::atomic_thread_fence(std::memory_order_acquire);
195 if (NeedSizeEstimate) {
196 return CalculateSize(front, back);
199 unsigned maybe_zero = ((front ^ back) & kMask2);
202 eigen_assert((CalculateSize(front, back) == 0) == (maybe_zero == 0));
208 EIGEN_ALWAYS_INLINE
unsigned CalculateSize(
unsigned front,
unsigned back)
const {
209 int size = (front & kMask2) - (back & kMask2);
211 if (size < 0) size += 2 * kSize;
216 if (size >
static_cast<int>(kSize)) size = kSize;
217 return static_cast<unsigned>(size);
220 RunQueue(
const RunQueue&) =
delete;
221 void operator=(
const RunQueue&) =
delete;
Namespace containing all symbols from the Eigen library.
Definition Core:137