Eigen::RunQueue< Work, kSize > Class Template Reference

Classes

struct  Elem
 

Public Member Functions

bool Empty () const
 
void Flush ()
 
Work PopBack ()
 
unsigned PopBackHalf (std::vector< Work > *result)
 
Work PopFront ()
 
Work PushBack (Work w)
 
Work PushFront (Work w)
 
 RunQueue ()
 
unsigned Size () const
 
 ~RunQueue ()
 

Private Types

enum  {
  kEmpty ,
  kBusy ,
  kReady
}
 

Private Member Functions

EIGEN_ALWAYS_INLINE unsigned CalculateSize (unsigned front, unsigned back) const
 
void operator= (const RunQueue &)=delete
 
 RunQueue (const RunQueue &)=delete
 
template<bool NeedSizeEstimate>
unsigned SizeOrNotEmpty () const
 

Private Attributes

Elem array_ [kSize]
 
std::atomic< unsigned > back_
 
std::atomic< unsigned > front_
 
EIGEN_MUTEX mutex_
 

Static Private Attributes

static const unsigned kMask
 
static const unsigned kMask2
 

Detailed Description

template<typename Work, unsigned kSize>
class Eigen::RunQueue< Work, kSize >

Definition at line 40 of file RunQueue.h.

Member Enumeration Documentation

◆ anonymous enum

template<typename Work , unsigned kSize>
anonymous enum
private
Enumerator
kEmpty 
kBusy 
kReady 

Definition at line 172 of file RunQueue.h.

172  {
173  kEmpty,
174  kBusy,
175  kReady,
176  };

Constructor & Destructor Documentation

◆ RunQueue() [1/2]

template<typename Work , unsigned kSize>
Eigen::RunQueue< Work, kSize >::RunQueue ( )
inline

Definition at line 42 of file RunQueue.h.

42  : front_(0), back_(0) {
43  // require power-of-two for fast masking
44  eigen_plain_assert((kSize & (kSize - 1)) == 0);
45  eigen_plain_assert(kSize > 2); // why would you do this?
46  eigen_plain_assert(kSize <= (64 << 10)); // leave enough space for counter
47  for (unsigned i = 0; i < kSize; i++)
48  array_[i].state.store(kEmpty, std::memory_order_relaxed);
49  }
#define eigen_plain_assert(condition)
Definition: Assert.h:156
std::atomic< unsigned > front_
Definition: RunQueue.h:185
std::atomic< unsigned > back_
Definition: RunQueue.h:186
Elem array_[kSize]
Definition: RunQueue.h:187

◆ ~RunQueue()

template<typename Work , unsigned kSize>
Eigen::RunQueue< Work, kSize >::~RunQueue ( )
inline

Definition at line 51 of file RunQueue.h.

51 { eigen_plain_assert(Size() == 0); }
unsigned Size() const
Definition: RunQueue.h:152

◆ RunQueue() [2/2]

template<typename Work , unsigned kSize>
Eigen::RunQueue< Work, kSize >::RunQueue ( const RunQueue< Work, kSize > &  )
privatedelete

Member Function Documentation

◆ CalculateSize()

template<typename Work , unsigned kSize>
EIGEN_ALWAYS_INLINE unsigned Eigen::RunQueue< Work, kSize >::CalculateSize ( unsigned  front,
unsigned  back 
) const
inlineprivate

Definition at line 220 of file RunQueue.h.

220  {
221  int size = (front & kMask2) - (back & kMask2);
222  // Fix overflow.
223  if (size < 0) size += 2 * kSize;
224  // Order of modification in push/pop is crafted to make the queue look
225  // larger than it is during concurrent modifications. E.g. push can
226  // increment size before the corresponding pop has decremented it.
227  // So the computed size can be up to kSize + 1, fix it.
228  if (size > static_cast<int>(kSize)) size = kSize;
229  return static_cast<unsigned>(size);
230  }
static const unsigned kMask2
Definition: RunQueue.h:167

◆ Empty()

template<typename Work , unsigned kSize>
bool Eigen::RunQueue< Work, kSize >::Empty ( ) const
inline

Definition at line 156 of file RunQueue.h.

156 { return SizeOrNotEmpty<false>() == 0; }

◆ Flush()

template<typename Work , unsigned kSize>
void Eigen::RunQueue< Work, kSize >::Flush ( )
inline

Definition at line 159 of file RunQueue.h.

159  {
160  while (!Empty()) {
161  PopFront();
162  }
163  }
Work PopFront()
Definition: RunQueue.h:70
bool Empty() const
Definition: RunQueue.h:156

◆ operator=()

template<typename Work , unsigned kSize>
void Eigen::RunQueue< Work, kSize >::operator= ( const RunQueue< Work, kSize > &  )
privatedelete

◆ PopBack()

template<typename Work , unsigned kSize>
Work Eigen::RunQueue< Work, kSize >::PopBack ( )
inline

Definition at line 102 of file RunQueue.h.

102  {
103  if (Empty()) return Work();
104  EIGEN_MUTEX_LOCK lock(mutex_);
105  unsigned back = back_.load(std::memory_order_relaxed);
106  Elem* e = &array_[back & kMask];
107  uint8_t s = e->state.load(std::memory_order_relaxed);
108  if (s != kReady ||
109  !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire))
110  return Work();
111  Work w = std::move(e->w);
112  e->state.store(kEmpty, std::memory_order_release);
113  back_.store(back + 1 + (kSize << 1), std::memory_order_relaxed);
114  return w;
115  }
Array< double, 1, 3 > e(1./3., 0.5, 2.)
RowVector3d w
#define EIGEN_MUTEX_LOCK
Definition: ThreadPool:58
EIGEN_MUTEX mutex_
Definition: RunQueue.h:177
static const unsigned kMask
Definition: RunQueue.h:166
std::uint8_t uint8_t
Definition: Meta.h:35

◆ PopBackHalf()

template<typename Work , unsigned kSize>
unsigned Eigen::RunQueue< Work, kSize >::PopBackHalf ( std::vector< Work > *  result)
inline

Definition at line 119 of file RunQueue.h.

119  {
120  if (Empty()) return 0;
121  EIGEN_MUTEX_LOCK lock(mutex_);
122  unsigned back = back_.load(std::memory_order_relaxed);
123  unsigned size = Size();
124  unsigned mid = back;
125  if (size > 1) mid = back + (size - 1) / 2;
126  unsigned n = 0;
127  unsigned start = 0;
128  for (; static_cast<int>(mid - back) >= 0; mid--) {
129  Elem* e = &array_[mid & kMask];
130  uint8_t s = e->state.load(std::memory_order_relaxed);
131  if (n == 0) {
132  if (s != kReady || !e->state.compare_exchange_strong(
133  s, kBusy, std::memory_order_acquire))
134  continue;
135  start = mid;
136  } else {
137  // Note: no need to store temporal kBusy, we exclusively own these
138  // elements.
140  }
141  result->push_back(std::move(e->w));
142  e->state.store(kEmpty, std::memory_order_release);
143  n++;
144  }
145  if (n != 0)
146  back_.store(start + 1 + (kSize << 1), std::memory_order_relaxed);
147  return n;
148  }
int n

◆ PopFront()

template<typename Work , unsigned kSize>
Work Eigen::RunQueue< Work, kSize >::PopFront ( )
inline

Definition at line 70 of file RunQueue.h.

70  {
71  unsigned front = front_.load(std::memory_order_relaxed);
72  Elem* e = &array_[(front - 1) & kMask];
73  uint8_t s = e->state.load(std::memory_order_relaxed);
74  if (s != kReady ||
75  !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire))
76  return Work();
77  Work w = std::move(e->w);
78  e->state.store(kEmpty, std::memory_order_release);
79  front = ((front - 1) & kMask2) | (front & ~kMask2);
80  front_.store(front, std::memory_order_relaxed);
81  return w;
82  }

◆ PushBack()

template<typename Work , unsigned kSize>
Work Eigen::RunQueue< Work, kSize >::PushBack ( Work  w)
inline

Definition at line 86 of file RunQueue.h.

86  {
88  unsigned back = back_.load(std::memory_order_relaxed);
89  Elem* e = &array_[(back - 1) & kMask];
90  uint8_t s = e->state.load(std::memory_order_relaxed);
91  if (s != kEmpty ||
92  !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire))
93  return w;
94  back = ((back - 1) & kMask2) | (back & ~kMask2);
95  back_.store(back, std::memory_order_relaxed);
96  e->w = std::move(w);
97  e->state.store(kReady, std::memory_order_release);
98  return Work();
99  }

◆ PushFront()

template<typename Work , unsigned kSize>
Work Eigen::RunQueue< Work, kSize >::PushFront ( Work  w)
inline

Definition at line 55 of file RunQueue.h.

55  {
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 ||
60  !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire))
61  return w;
62  front_.store(front + 1 + (kSize << 1), std::memory_order_relaxed);
63  e->w = std::move(w);
64  e->state.store(kReady, std::memory_order_release);
65  return Work();
66  }

◆ Size()

template<typename Work , unsigned kSize>
unsigned Eigen::RunQueue< Work, kSize >::Size ( ) const
inline

Definition at line 152 of file RunQueue.h.

152 { return SizeOrNotEmpty<true>(); }

◆ SizeOrNotEmpty()

template<typename Work , unsigned kSize>
template<bool NeedSizeEstimate>
unsigned Eigen::RunQueue< Work, kSize >::SizeOrNotEmpty ( ) const
inlineprivate

Definition at line 193 of file RunQueue.h.

193  {
194  // Emptiness plays critical role in thread pool blocking. So we go to great
195  // effort to not produce false positives (claim non-empty queue as empty).
196  unsigned front = front_.load(std::memory_order_acquire);
197  for (;;) {
198  // Capture a consistent snapshot of front/tail.
199  unsigned back = back_.load(std::memory_order_acquire);
200  unsigned front1 = front_.load(std::memory_order_relaxed);
201  if (front != front1) {
202  front = front1;
203  std::atomic_thread_fence(std::memory_order_acquire);
204  continue;
205  }
206  if (NeedSizeEstimate) {
207  return CalculateSize(front, back);
208  } else {
209  // This value will be 0 if the queue is empty, and undefined otherwise.
210  unsigned maybe_zero = ((front ^ back) & kMask2);
211  // Queue size estimate must agree with maybe zero check on the queue
212  // empty/non-empty state.
213  eigen_assert((CalculateSize(front, back) == 0) == (maybe_zero == 0));
214  return maybe_zero;
215  }
216  }
217  }
#define eigen_assert(x)
Definition: Macros.h:902
EIGEN_ALWAYS_INLINE unsigned CalculateSize(unsigned front, unsigned back) const
Definition: RunQueue.h:220

Member Data Documentation

◆ array_

template<typename Work , unsigned kSize>
Elem Eigen::RunQueue< Work, kSize >::array_[kSize]
private

Definition at line 187 of file RunQueue.h.

◆ back_

template<typename Work , unsigned kSize>
std::atomic<unsigned> Eigen::RunQueue< Work, kSize >::back_
private

Definition at line 186 of file RunQueue.h.

◆ front_

template<typename Work , unsigned kSize>
std::atomic<unsigned> Eigen::RunQueue< Work, kSize >::front_
private

Definition at line 185 of file RunQueue.h.

◆ kMask

template<typename Work , unsigned kSize>
const unsigned Eigen::RunQueue< Work, kSize >::kMask
staticprivate

Definition at line 166 of file RunQueue.h.

◆ kMask2

template<typename Work , unsigned kSize>
const unsigned Eigen::RunQueue< Work, kSize >::kMask2
staticprivate

Definition at line 167 of file RunQueue.h.

◆ mutex_

template<typename Work , unsigned kSize>
EIGEN_MUTEX Eigen::RunQueue< Work, kSize >::mutex_
private

Definition at line 177 of file RunQueue.h.


The documentation for this class was generated from the following file: