nlib
LockFree.h
[詳解]
1 
2 /*--------------------------------------------------------------------------------*
3  Project: CrossRoad
4  Copyright (C)Nintendo All rights reserved.
5 
6  These coded instructions, statements, and computer programs contain proprietary
7  information of Nintendo and/or its licensed developers and are protected by
8  national and international copyright laws. They may not be disclosed to third
9  parties or copied or duplicated in any form, in whole or in part, without the
10  prior written consent of Nintendo.
11 
12  The content herein is highly confidential and should be handled accordingly.
13  *--------------------------------------------------------------------------------*/
14 
15 #pragma once
16 #ifndef INCLUDE_NN_NLIB_LOCKFREE_H_
17 #define INCLUDE_NN_NLIB_LOCKFREE_H_
18 
19 #include <new>
20 #include "nn/nlib/Config.h"
21 #include "nn/nlib/TypeTraits.h"
22 #include "nn/nlib/UniquePtr.h"
24 #include "nn/nlib/Swap.h"
25 
26 NLIB_NAMESPACE_BEGIN
27 
28 template<class T1, class T2 = void>
29 struct LockFreePlaceHolder {
30  T1 data; // T1 must be POD
31  union next_type {
32  uintptr_t aba_ptr;
33  LockFreePlaceHolder<T1, T2>* raw_ptr;
34  } next;
35  T2 aux;
36  void Init(const T1& elem) NLIB_NOEXCEPT NLIB_NO_TSAN {
37  data = elem;
38  aux = T2();
39  }
40 };
41 
42 template<class T1>
43 struct LockFreePlaceHolder<T1, void> {
44  T1 data; // T1 must be POD
45  union next_type {
46  uintptr_t aba_ptr;
47  LockFreePlaceHolder<T1, void>* raw_ptr;
48  } next;
49  void Init(const T1& elem) NLIB_NOEXCEPT NLIB_NO_TSAN {
50  data = elem;
51  }
52 };
53 
54 template<class T1, class T2 = void>
55 class LockFreePlaceHolderPool NLIB_FINAL {
56  public:
57 #if !defined(CAFE) && !defined(NN_PLATFORM_CTR)
58  // some old compilers may complain that T1 is incomplete type even if it is not.
59  NLIB_STATIC_ASSERT(IsPod<T1>::value);
60 #endif
61  LockFreePlaceHolderPool() NLIB_NOEXCEPT : invariant_(0), mask_(0), mem_(nullptr) {}
62  ~LockFreePlaceHolderPool() NLIB_NOEXCEPT { delete[] mem_; }
63  errno_t Init(size_t count) NLIB_NOEXCEPT;
64  NLIB_ALWAYS_INLINE LockFreePlaceHolder<T1, T2>* CalcPtr(uintptr_t aba) const NLIB_NOEXCEPT {
65  return reinterpret_cast<LockFreePlaceHolder<T1, T2>*>((aba & mask_) | invariant_);
66  }
67  NLIB_ALWAYS_INLINE bool IsNull(uintptr_t aba) const NLIB_NOEXCEPT {
68  return aba & 1;
69  }
70  NLIB_ALWAYS_INLINE LockFreePlaceHolder<T1, T2>* Alloc() NLIB_NOEXCEPT NLIB_NO_TSAN {
71  LockFreePlaceHolder<T1, T2>* ptr;
72  uintptr_t expected = Load(&freelist_);
73  for (;;) {
74  if (NLIB_UNLIKELY(IsNull(expected))) return nullptr;
75  ptr = this->CalcPtr(expected);
76  uintptr_t desired = Load(&ptr->next.aba_ptr);
77  if (NLIB_LIKELY(Cas(&freelist_, &expected, &desired, 1)))
78  break;
79  }
80  uintptr_t mask = mask_;
81  ptr->next.aba_ptr = (ptr->next.aba_ptr & ~mask) + (mask + 2);
82  return ptr;
83  }
84  NLIB_ALWAYS_INLINE void Free(LockFreePlaceHolder<T1, T2>* p) NLIB_NOEXCEPT NLIB_NO_TSAN {
85  uintptr_t mask = mask_;
86  uintptr_t desired = reinterpret_cast<uintptr_t>(p);
87  uintptr_t expected = Load(&freelist_);
88  uintptr_t base = (p->next.aba_ptr & ~mask) + (mask + 1);
89  for (;;) {
90  Store(&p->next.aba_ptr, base | (expected & mask));
91  // must comfirm p->next written
92  if (NLIB_LIKELY(Cas(&freelist_, &expected, &desired, 1, NLIB_ATOMIC_RELEASE)))
93  break;
94  }
95  }
96  NLIB_ALWAYS_INLINE LockFreePlaceHolder<T1, T2>* AllocUnsafe() NLIB_NOEXCEPT {
97  uintptr_t expected = freelist_;
98  if (NLIB_UNLIKELY(IsNull(expected))) return nullptr;
99  LockFreePlaceHolder<T1, T2>* ptr = this->CalcPtr(expected);
100  freelist_ = ptr->next.aba_ptr;
101  ptr->next.aba_ptr = 1;
102  return ptr;
103  }
104  NLIB_ALWAYS_INLINE void FreeUnsafe(LockFreePlaceHolder<T1, T2>* p) NLIB_NOEXCEPT {
105  p->next.aba_ptr = freelist_;
106  freelist_ = reinterpret_cast<uintptr_t>(p);
107  }
108  NLIB_ALWAYS_INLINE uintptr_t Load(uintptr_t* ptr) NLIB_NOEXCEPT NLIB_NO_TSAN {
109  void* val = nlib_atomic_loadptr(reinterpret_cast<void**>(ptr), NLIB_ATOMIC_RELAXED);
110  return reinterpret_cast<uintptr_t>(val);
111  }
112  NLIB_ALWAYS_INLINE uintptr_t Load(uintptr_t* ptr, int memorder) NLIB_NOEXCEPT NLIB_NO_TSAN {
113  void* val = nlib_atomic_loadptr(reinterpret_cast<void**>(ptr), memorder);
114  return reinterpret_cast<uintptr_t>(val);
115  }
116  NLIB_ALWAYS_INLINE void Store(uintptr_t* ptr, uintptr_t value) NLIB_NOEXCEPT NLIB_NO_TSAN {
117  nlib_atomic_storeptr(reinterpret_cast<void**>(ptr),
118  reinterpret_cast<void*>(value),
120  }
121  NLIB_ALWAYS_INLINE void Store(uintptr_t* ptr, uintptr_t value, int memorder)
122  NLIB_NOEXCEPT NLIB_NO_TSAN {
123  nlib_atomic_storeptr(reinterpret_cast<void**>(ptr),
124  reinterpret_cast<void*>(value),
125  memorder);
126  }
127  NLIB_ALWAYS_INLINE int Cas(uintptr_t* ptr, uintptr_t* expected, uintptr_t* desired, int weak,
128  int success_memorder, int failure_memorder)
129  NLIB_NOEXCEPT NLIB_NO_TSAN {
130  uintptr_t mask = mask_;
131  *desired = ((*desired & mask) | (mask + 1)) + (*expected & ~mask);
132  int rval = nlib_atomic_compare_exchangeptr(reinterpret_cast<void**>(ptr),
133  reinterpret_cast<void**>(expected),
134  reinterpret_cast<void*>(*desired),
135  weak, success_memorder, failure_memorder);
136  return rval;
137  }
138  NLIB_ALWAYS_INLINE int Cas(uintptr_t* ptr, uintptr_t* expected, uintptr_t* desired, int weak,
139  int success_memorder) NLIB_NOEXCEPT {
140  return Cas(ptr, expected, desired, weak, success_memorder, NLIB_ATOMIC_RELAXED);
141  }
142  NLIB_ALWAYS_INLINE int Cas(uintptr_t* ptr, uintptr_t* expected, uintptr_t* desired,
143  int weak) NLIB_NOEXCEPT {
144  return Cas(ptr, expected, desired, weak, NLIB_ATOMIC_RELAXED, NLIB_ATOMIC_RELAXED);
145  }
146  void SwapUnsafe(LockFreePlaceHolderPool& rhs) NLIB_NOEXCEPT { // NOLINT
147  std::swap(freelist_, rhs.freelist_);
148  std::swap(invariant_, rhs.invariant_);
149  std::swap(mask_, rhs.mask_);
150  std::swap(mem_, rhs.mem_);
151  }
152 
153  public:
154  errno_t Push(uintptr_t* stack, const T1& elem) NLIB_NOEXCEPT;
155  errno_t Pop(uintptr_t* stack, T1* elem) NLIB_NOEXCEPT;
156  errno_t Enqueue(uintptr_t* tail, const T1& elem) NLIB_NOEXCEPT;
157  errno_t Dequeue(uintptr_t* head, uintptr_t* tail, T1* elem) NLIB_NOEXCEPT;
158  errno_t PushUnsafe(uintptr_t* stack, const T1& elem) NLIB_NOEXCEPT {
159  typedef LockFreePlaceHolder<T1, T2> item_type;
160  item_type* item_ptr = AllocUnsafe();
161  if (NLIB_UNLIKELY(!item_ptr)) return EAGAIN;
162 
163  // point of no failure
164  item_ptr->data = elem;
165  item_ptr->next.aba_ptr = *stack;
166  *stack = reinterpret_cast<uintptr_t>(item_ptr);
167  return 0;
168  }
169  errno_t PopUnsafe(uintptr_t* stack, T1* elem) NLIB_NOEXCEPT {
170  if (NLIB_UNLIKELY(IsNull(*stack))) return EAGAIN;
171  LockFreePlaceHolder<T1, T2>* ptr = CalcPtr(*stack);
172  *elem = ptr->data;
173  *stack = ptr->next.aba_ptr;
174  FreeUnsafe(ptr);
175  return 0;
176  }
177  errno_t EnqueueUnsafe(uintptr_t* tail, const T1& elem) NLIB_NOEXCEPT {
178  LockFreePlaceHolder<T1, T2>* item_ptr = AllocUnsafe();
179  if (NLIB_UNLIKELY(!item_ptr)) return EAGAIN;
180 
181  // point of no failure
182  item_ptr->data = elem;
183  CalcPtr(*tail)->next.aba_ptr = reinterpret_cast<uintptr_t>(item_ptr);
184  *tail = reinterpret_cast<uintptr_t>(item_ptr);
185  return 0;
186  }
187  errno_t DequeueUnsafe(uintptr_t* head, uintptr_t* tail, T1* elem) NLIB_NOEXCEPT {
188  typedef LockFreePlaceHolder<T1, T2> item_type;
189  item_type* first_ptr = CalcPtr(*head);
190  item_type* last_ptr = CalcPtr(*tail);
191  if (first_ptr == last_ptr) return EAGAIN;
192 
193  uintptr_t first_next = first_ptr->next.aba_ptr;
194  item_type* first_next_ptr = CalcPtr(first_next);
195  *elem = first_next_ptr->data;
196  *head = first_next;
197  FreeUnsafe(first_ptr);
198  return 0;
199  }
200 
201  private:
202  uintptr_t freelist_;
203  uintptr_t invariant_;
204  uintptr_t mask_;
205  LockFreePlaceHolder<T1, T2>* mem_;
206  NLIB_DISALLOW_COPY_AND_ASSIGN(LockFreePlaceHolderPool);
207 };
208 
209 template<class T1, class T2>
210 errno_t LockFreePlaceHolderPool<T1, T2>::Init(size_t count) NLIB_NOEXCEPT {
211  if (NLIB_UNLIKELY(mem_)) return EALREADY;
212  LockFreePlaceHolder<T1, T2>* mem = new (std::nothrow) LockFreePlaceHolder<T1, T2>[count];
213  if (NLIB_UNLIKELY(!mem)) return ENOMEM;
214  uintptr_t freelist = 1;
215 #ifdef NLIB_64BIT
216  for (size_t j = 0; j < 4; ++j) {
217  for (size_t i = j; i < count; i += 4) {
218  mem[i].next.aba_ptr = freelist;
219  mem[i].data = T1();
220  freelist = reinterpret_cast<uintptr_t>(&mem[i]);
221  }
222  }
223 #else
224  for (size_t j = 0; j < 8; ++j) {
225  for (size_t i = j; i < count; i += 8) {
226  mem[i].next.aba_ptr = freelist;
227  mem[i].data = T1();
228  freelist = reinterpret_cast<uintptr_t>(&mem[i]);
229  }
230  }
231 #endif
232  uintptr_t first = reinterpret_cast<uintptr_t>(mem);
233  uintptr_t last = reinterpret_cast<uintptr_t>(mem + count);
234 #ifdef NLIB_64BIT
235  int sft = nlib_clz64(first ^ last);
236 #else
237  int sft = nlib_clz32(first ^ last);
238 #endif
239  freelist_ = freelist;
240  mask_ = (static_cast<uintptr_t>(0) - 1) >> sft;
241  invariant_ = first & ~mask_;
242  mem_ = mem;
243  return 0;
244 }
245 
246 template<class T1, class T2>
247 NLIB_ALWAYS_INLINE errno_t LockFreePlaceHolderPool<T1, T2>::Push(
248  uintptr_t* stack, const T1& elem) NLIB_NOEXCEPT NLIB_NO_TSAN {
249  typedef LockFreePlaceHolder<T1, T2> item_type;
250  item_type* item_ptr = Alloc();
251  if (NLIB_UNLIKELY(!item_ptr)) return EAGAIN;
252 
253  // point of no failure
254  item_ptr->data = elem;
255  uintptr_t mask = mask_;
256  uintptr_t desired = reinterpret_cast<uintptr_t>(item_ptr);
257  uintptr_t expected = Load(&freelist_);
258  uintptr_t base = (item_ptr->next.aba_ptr & ~mask) + (mask + 1);
259  for (;;) {
260  Store(&item_ptr->next.aba_ptr, base | (expected & mask));
261  // must comfirm p->next written
262  if (NLIB_LIKELY(Cas(stack, &expected, &desired, 1, NLIB_ATOMIC_RELEASE)))
263  break;
264  }
265  return 0;
266 }
267 
268 template<class T1, class T2>
269 NLIB_ALWAYS_INLINE errno_t LockFreePlaceHolderPool<T1, T2>::Pop(
270  uintptr_t* stack, T1* elem) NLIB_NOEXCEPT NLIB_NO_TSAN {
271  LockFreePlaceHolder<T1, T2>* ptr;
272  uintptr_t expected = Load(stack);
273  for (;;) {
274  if (NLIB_UNLIKELY(IsNull(expected))) return EAGAIN;
275  ptr = this->CalcPtr(expected);
276  uintptr_t desired = Load(&ptr->next.aba_ptr);
277  if (NLIB_LIKELY(Cas(stack, &expected, &desired, 1)))
278  break;
279  }
280  *elem = ptr->data;
281  Free(ptr);
282  return 0;
283 }
284 
285 template<class T1, class T2>
286 NLIB_ALWAYS_INLINE errno_t LockFreePlaceHolderPool<T1, T2>::Enqueue(
287  uintptr_t* tail, const T1& elem) NLIB_NOEXCEPT NLIB_NO_TSAN {
288  LockFreePlaceHolder<T1, T2>* item_ptr = Alloc();
289  if (NLIB_UNLIKELY(!item_ptr)) return EAGAIN;
290 
291  // point of no failure
292  item_ptr->Init(elem);
293 #if !defined(_M_IX86) && !defined(_M_AMD64) && !defined(__i386__) && !defined(__x86_64__)
295 #endif
296  uintptr_t last = Load(tail);
297  for (;;) {
298  uintptr_t* last_next_ptr = &CalcPtr(last)->next.aba_ptr;
299  uintptr_t last_next = Load(last_next_ptr,
300  NLIB_ATOMIC_ACQUIRE); // before last_new is loaded
301  uintptr_t last_new = Load(tail);
302  if (NLIB_LIKELY(last == last_new)) {
303  if (NLIB_LIKELY(IsNull(last_next))) {
304  if (NLIB_LIKELY(Cas(last_next_ptr, &last_next,
305  reinterpret_cast<uintptr_t*>(&item_ptr),
306  1, NLIB_ATOMIC_ACQUIRE))) {
307  // Update tail
308  Cas(tail, &last, reinterpret_cast<uintptr_t*>(&item_ptr), 0);
309  return 0;
310  }
311  } else {
312  // Update tail and retry
313  if (NLIB_LIKELY(Cas(tail, &last, &last_next, 0))) {
314  last = last_next;
315  }
316  }
317  } else {
318  last = last_new;
319  }
320  }
321 }
322 
323 template<class T1, class T2>
324 NLIB_ALWAYS_INLINE errno_t LockFreePlaceHolderPool<T1, T2>::Dequeue(
325  uintptr_t* head, uintptr_t* tail, T1* elem) NLIB_NOEXCEPT NLIB_NO_TSAN {
326  typedef LockFreePlaceHolder<T1, T2> item_type;
327  // Load(head), then Load(tail)
328  uintptr_t first = Load(head, NLIB_ATOMIC_ACQUIRE);
329  uintptr_t last = Load(tail);
330  for (;;) {
331  item_type* first_ptr = CalcPtr(first);
332  item_type* last_ptr = CalcPtr(last);
333  uintptr_t first_next = Load(&first_ptr->next.aba_ptr,
334  NLIB_ATOMIC_ACQUIRE); // before first_new is loaded
335  uintptr_t first_new = Load(head);
336  if (NLIB_LIKELY(first == first_new)) {
337  if (NLIB_UNLIKELY(first_ptr == last_ptr)) {
338  if (NLIB_UNLIKELY(IsNull(first_next))) return EAGAIN;
339  // Update tail and retry
340  first = Load(head, NLIB_ATOMIC_ACQUIRE);
341  if (NLIB_LIKELY(Cas(tail, &last, &first_next, 0))) {
342  last = first_next;
343  }
344  } else {
345  item_type* first_next_ptr = CalcPtr(first_next);
346  *elem = first_next_ptr->data;
347  if (NLIB_LIKELY(Cas(head, &first, &first_next, 0))) {
348  Free(CalcPtr(first));
349  return 0;
350  }
351  first = Load(head, NLIB_ATOMIC_ACQUIRE);
352  last = Load(tail);
353  }
354  } else {
355  first = first_new;
356  last = Load(tail);
357  }
358  }
359 }
360 
361 template<size_t N>
363  public:
364  LockFreePipe() NLIB_NOEXCEPT : ofs_read_(0), ofs_write_(0) {}
365  size_t GetBufferSize() NLIB_NOEXCEPT {
366  NLIB_STATIC_ASSERT(N > 0);
367  NLIB_STATIC_ASSERT((N & (N - 1)) == 0);
368  NLIB_STATIC_ASSERT(N < INT32_MAX);
369  return N;
370  }
371  NLIB_ALWAYS_INLINE errno_t Read(void* dest, size_t nbytes) NLIB_NOEXCEPT {
372  uint32_t rofs = this->Load(&ofs_read_, NLIB_ATOMIC_RELAXED);
373  uint32_t wofs = this->Load(&ofs_write_, NLIB_ATOMIC_ACQUIRE);
374  // read ofs_write_, then read buffer_[rofs_actual]
375 
376  if (NLIB_UNLIKELY(nbytes > wofs - rofs)) return EAGAIN;
377  uint32_t rofs_actual = rofs & (N - 1);
378 
379  size_t ntail = N - rofs_actual;
380  if (ntail >= nbytes) {
381  // ARMCC needs this cast.
382  nlib_memcpy(dest,
383  nbytes,
384  reinterpret_cast<const void*>(&buffer_[rofs_actual]),
385  nbytes);
386  } else {
387  nlib_memcpy(dest,
388  nbytes,
389  reinterpret_cast<const void*>(&buffer_[rofs_actual]),
390  ntail);
391  nlib_memcpy(reinterpret_cast<void*>(reinterpret_cast<uint8_t*>(dest) + ntail),
392  nbytes - ntail,
393  reinterpret_cast<void*>(&buffer_[0]),
394  nbytes - ntail);
395  }
396  rofs += static_cast<uint32_t>(nbytes);
397 
398  // must not be reordered
399  this->Store(&ofs_read_, rofs, NLIB_ATOMIC_RELEASE);
400  return 0;
401  }
402  NLIB_ALWAYS_INLINE errno_t Write(const void* src, size_t nbytes) NLIB_NOEXCEPT {
403  uint32_t wofs = this->Load(&ofs_write_, NLIB_ATOMIC_RELAXED);
404  uint32_t rofs = this->Load(&ofs_read_, NLIB_ATOMIC_ACQUIRE);
405  // read ofs_read_, then write buffer_[wofs_actual]
406 
407  if (NLIB_UNLIKELY(nbytes > N - (wofs - rofs))) return EAGAIN;
408  uint32_t wofs_actual = wofs & (N - 1);
409 
410  size_t ntail = N - wofs_actual;
411  if (ntail >= nbytes) {
412  nlib_memcpy(reinterpret_cast<void*>(&buffer_[wofs_actual]),
413  nbytes,
414  src,
415  nbytes);
416  } else {
417  nlib_memcpy(reinterpret_cast<void*>(&buffer_[wofs_actual]),
418  ntail,
419  src,
420  ntail);
421  nlib_memcpy(reinterpret_cast<void*>(&buffer_[0]),
422  nbytes - ntail,
423  reinterpret_cast<const void*>(
424  reinterpret_cast<const uint8_t*>(src) + ntail),
425  nbytes - ntail);
426  }
427  wofs += static_cast<uint32_t>(nbytes);
428 
429  // must not be reordered
430  this->Store(&ofs_write_, wofs, NLIB_ATOMIC_RELEASE);
431  return 0;
432  }
433 
434  private:
435  NLIB_ALWAYS_INLINE uint32_t Load(uint32_t* p, int memorder) NLIB_NOEXCEPT {
436  return static_cast<uint32_t>(nlib_atomic_load32(
437  reinterpret_cast<int32_t*>(p), memorder));
438  }
439  NLIB_ALWAYS_INLINE void Store(uint32_t* p, uint32_t value, int memorder) NLIB_NOEXCEPT {
440  nlib_atomic_store32(reinterpret_cast<int32_t*>(p),
441  static_cast<int32_t>(value), memorder);
442  }
443 
444  uint32_t ofs_read_;
445  uint32_t ofs_write_;
446  uint8_t buffer_[N];
448 };
449 
450 template<class T>
452  public:
453  T* operator()() NLIB_NOEXCEPT { return new (std::nothrow) T(); }
454 };
455 
456 template<class T>
458  public:
459  void operator()(T* ptr) NLIB_NOEXCEPT { delete ptr; }
460 };
461 
462 template<class T>
464  public:
465  typedef T* PopType;
466  LockFreeStack() NLIB_NOEXCEPT : top_(0), pool_() {}
467  ~LockFreeStack() NLIB_NOEXCEPT {
468  // T is POD, and not pointer
469  }
470  // NOT thread safe
471  errno_t Init(size_t count) NLIB_NOEXCEPT {
472  errno_t e = pool_.Init(count);
473  if (NLIB_UNLIKELY(e != 0)) return e;
474  top_ = 1;
475  return 0;
476  }
477  errno_t Push(const T& x) NLIB_NOEXCEPT { return pool_.Push(&top_, x); }
478  errno_t Pop(PopType x) NLIB_NOEXCEPT { return pool_.Pop(&top_, x); }
479  // NOT thread safe
480  errno_t PushUnsafe(const T& x) NLIB_NOEXCEPT { return pool_.PushUnsafe(&top_, x); }
481  // NOT thread safe
482  errno_t PopUnsafe(PopType x) NLIB_NOEXCEPT { return pool_.PopUnsafe(&top_, x); }
483  void SwapUnsafe(LockFreeStack& rhs) NLIB_NOEXCEPT { // NOLINT
484  std::swap(top_, rhs.top_);
485  pool_.SwapUnsafe(rhs.pool_);
486  }
487 
488  private:
489  uintptr_t top_;
490  LockFreePlaceHolderPool<T> pool_;
491 };
492 
493 template<class T>
494 class LockFreeStack<T*> NLIB_FINAL {
495  public:
497  LockFreeStack() NLIB_NOEXCEPT : top_(0), pool_() {}
498  ~LockFreeStack() NLIB_NOEXCEPT {
499  if (top_ != 0) {
500  T* elem;
501  while (0 == pool_.PopUnsafe(&top_, &elem)) {
502  DestructorForLockFree<T>()(elem);
503  }
504  }
505  }
506  // NOT thread safe
507  errno_t Init(size_t count) NLIB_NOEXCEPT {
508  errno_t e = pool_.Init(count);
509  if (NLIB_UNLIKELY(e != 0)) return e;
510  top_ = 1;
511  return 0;
512  }
513  errno_t Push(T* obj) NLIB_NOEXCEPT { return pool_.Push(&top_, obj); }
514  errno_t Pop(PopType& obj) NLIB_NOEXCEPT { // NOLINT
515  T* x;
516  errno_t e = pool_.Pop(&top_, &x);
517  if (e != 0) return e;
518  obj.reset(x);
519  return 0;
520  }
521  // NOT thread safe
522  errno_t PushUnsafe(T* obj) NLIB_NOEXCEPT { return pool_.PushUnsafe(&top_, obj); }
523  // NOT thread safe
524  errno_t PopUnsafe(PopType& obj) NLIB_NOEXCEPT { // NOLINT
525  T* x;
526  errno_t e = pool_.PopUnsafe(&top_, &x);
527  if (e != 0) return e;
528  obj.reset(x);
529  return 0;
530  }
531  void SwapUnsafe(LockFreeStack& rhs) NLIB_NOEXCEPT { // NOLINT
532  std::swap(top_, rhs.top_);
533  pool_.SwapUnsafe(rhs.pool_);
534  }
535 
536  private:
537  uintptr_t top_;
538  LockFreePlaceHolderPool<T*> pool_;
539 };
540 
541 template<class T>
543  public:
544  typedef T* DequeueType;
545  LockFreeQueue() NLIB_NOEXCEPT : head_(0), tail_(0), pool_() {}
546  ~LockFreeQueue() NLIB_NOEXCEPT {
547  // T is POD, and not pointer
548  }
549  // NOT thread safe
550  errno_t Init(size_t count) NLIB_NOEXCEPT {
551  errno_t e = pool_.Init(count + 1);
552  if (NLIB_UNLIKELY(e != 0)) return e;
553  head_ = tail_ = reinterpret_cast<uintptr_t>(pool_.AllocUnsafe());
554  return 0;
555  }
556  errno_t Enqueue(const T& x) NLIB_NOEXCEPT { return pool_.Enqueue(&tail_, x); }
557  errno_t Dequeue(DequeueType x) NLIB_NOEXCEPT { return pool_.Dequeue(&head_, &tail_, x); }
558  // NOT thread safe
559  errno_t EnqueueUnsafe(const T& x) NLIB_NOEXCEPT { return pool_.EnqueueUnsafe(&tail_, x); }
560  // NOT thread safe
561  errno_t DequeueUnsafe(DequeueType x) NLIB_NOEXCEPT {
562  return pool_.DequeueUnsafe(&head_, &tail_, x);
563  }
564  void SwapUnsafe(LockFreeQueue& rhs) NLIB_NOEXCEPT { // NOLINT
565  std::swap(head_, rhs.head_);
566  std::swap(tail_, rhs.tail_);
567  pool_.SwapUnsafe(rhs.pool_);
568  }
569 
570  private:
571  uintptr_t head_;
572  uintptr_t tail_;
573  LockFreePlaceHolderPool<T> pool_;
574 };
575 
576 template<class T>
577 class LockFreeQueue<T*> NLIB_FINAL {
578  public:
580  LockFreeQueue() NLIB_NOEXCEPT : head_(0), tail_(0), pool_() {}
581  ~LockFreeQueue() NLIB_NOEXCEPT {
582  if (head_ != 0) {
583  T* elem;
584  while (0 == pool_.DequeueUnsafe(&head_, &tail_, &elem)) {
585  DestructorForLockFree<T>()(elem);
586  }
587  }
588  }
589  // NOT thread safe
590  errno_t Init(size_t count) NLIB_NOEXCEPT {
591  errno_t e = pool_.Init(count + 1);
592  if (NLIB_UNLIKELY(e != 0)) return e;
593  head_ = tail_ = reinterpret_cast<uintptr_t>(pool_.AllocUnsafe());
594  return 0;
595  }
596  errno_t Enqueue(T* obj) NLIB_NOEXCEPT { return pool_.Enqueue(&tail_, obj); }
597  errno_t Dequeue(DequeueType& obj) NLIB_NOEXCEPT { // NOLINT
598  T* x;
599  errno_t e = pool_.Dequeue(&head_, &tail_, &x);
600  if (e != 0) return e;
601  obj.reset(x);
602  return 0;
603  }
604  // NOT thread safe
605  errno_t EnqueueUnsafe(T* x) NLIB_NOEXCEPT { return pool_.EnqueueUnsafe(&tail_, x); }
606  // NOT thread safe
607  errno_t DequeueUnsafe(DequeueType& obj) NLIB_NOEXCEPT { // NOLINT
608  T* x;
609  errno_t e = pool_.DequeueUnsafe(&head_, &tail_, &x);
610  if (e != 0) return e;
611  obj.reset(x);
612  return 0;
613  }
614  void SwapUnsafe(LockFreeQueue& rhs) NLIB_NOEXCEPT { // NOLINT
615  std::swap(head_, rhs.head_);
616  std::swap(tail_, rhs.tail_);
617  pool_.SwapUnsafe(rhs.pool_);
618  }
619 
620  private:
621  uintptr_t head_;
622  uintptr_t tail_;
623  LockFreePlaceHolderPool<T*> pool_;
624 };
625 
626 template<class T>
627 errno_t LockFreeInit(T** ptr) NLIB_NOEXCEPT NLIB_NONNULL;
628 
629 template<class T>
630 inline errno_t LockFreeInit(T** ptr) NLIB_NOEXCEPT {
631  NLIB_EINVAL_IFNULL(ptr);
632  void* pold = nlib_atomic_loadptr(reinterpret_cast<void**>(ptr), NLIB_ATOMIC_RELAXED);
633  if (pold) return 0;
634  T* obj = ConstructorForLockFree<T>()();
635  if (!obj) {
636  pold = nlib_atomic_loadptr(reinterpret_cast<void**>(ptr), NLIB_ATOMIC_RELAXED);
637  return pold ? 0 : EAGAIN;
638  }
639  if (nlib_atomic_compare_exchangeptr(reinterpret_cast<void**>(ptr),
640  &pold, reinterpret_cast<void*>(obj), 0,
642  return 0;
643  } else {
645  return 0;
646  }
647 }
648 
649 template<class T>
651  public:
653  LockFreePriorityQueue() NLIB_NOEXCEPT : mq_() {
654  mq_.raw_handle = 0;
655  }
656  ~LockFreePriorityQueue() NLIB_NOEXCEPT {
657  if (mq_.raw_handle != 0) (void)nlib_mq_close(mq_);
658  }
659  // NOT thread safe
660  errno_t Init(size_t max_size) NLIB_NOEXCEPT {
661  // not thread safe
662  if (mq_.raw_handle != 0) return EALREADY;
663  if (max_size > INT32_MAX) return EINVAL;
664  nlib_mq_attr attr;
665  attr.flag = NLIB_MQ_LOCKFREE;
666  attr.max_msg = static_cast<int32_t>(max_size);
667  attr.destructor = LockFreePriorityQueue::dtor;
668  return nlib_mq_open(&mq_, &attr);
669  }
670  // NOT thread safe
671  errno_t Close() NLIB_NOEXCEPT {
672  // not thread safe
673  nlib_mq mq = mq_;
674  mq_.raw_handle = 0;
675  return nlib_mq_close(mq);
676  }
677  errno_t Enqueue(T* obj, int prio) NLIB_NOEXCEPT {
678  // thread safe
679  return nlib_mq_send(mq_, obj, prio);
680  }
681  errno_t Dequeue(DequeueType& obj, int* prio) NLIB_NOEXCEPT { // NOLINT
682  // thread safe
683  T* x;
684  errno_t e = nlib_mq_receive(mq_, reinterpret_cast<nlib_mq_msg*>(&x), prio);
685  if (e != 0) return e;
686  obj.reset(x);
687  return 0;
688  }
689  void SwapUnsafe(LockFreePriorityQueue& rhs) NLIB_NOEXCEPT { // NOLINT
690  nlib_mq mq = rhs.mq_;
691  rhs.mq_ = mq_;
692  mq_ = mq;
693  }
694 
695  private:
696  static void dtor(nlib_mq_msg msg) {
697  T* obj = reinterpret_cast<T*>(msg);
699  }
700 
701  nlib_mq mq_;
702 };
703 
704 namespace detail {
705 
706 class LockFreeBroadcastQueueImpl {
707  typedef LockFreePlaceHolder<const void*, int32_t> item_type;
708 
709  public:
710  LockFreeBroadcastQueueImpl() NLIB_NOEXCEPT
711  : head_(1), tail_(1), listener_count_(0), pool_(), listeners_() {}
712  NLIB_VIS_PUBLIC ~LockFreeBroadcastQueueImpl() NLIB_NOEXCEPT;
713  NLIB_VIS_PUBLIC errno_t Init(size_t max_size, size_t listeners) NLIB_NOEXCEPT;
714  errno_t Enqueue(const void* msg) NLIB_NOEXCEPT {
715  // thread safe
716  return pool_.Enqueue(&tail_, msg);
717  }
718  errno_t Dequeue(int32_t listener_id, const void** msg) NLIB_NOEXCEPT {
719  // thread safe if listener_id is different
720  if (NLIB_UNLIKELY(listener_id < 0) ||
721  NLIB_UNLIKELY(listener_id >= listener_count_)) return ERANGE;
722  uintptr_t& pos = listeners_[listener_id];
723  item_type* item = pool_.CalcPtr(pos);
724  uintptr_t next = item->next.aba_ptr;
725  if (pool_.IsNull(next)) return ENOENT;
726  *msg = pool_.CalcPtr(next)->data;
727  pos = next;
729  return 0;
730  }
731  NLIB_VIS_PUBLIC const void* CheckAndRemove() NLIB_NOEXCEPT;
732  errno_t DeleteUnsafe(const void** msg) NLIB_NOEXCEPT {
733  if (pool_.IsNull(head_)) return ENOENT;
734  item_type* item = pool_.CalcPtr(head_);
735  const void* p = item->data;
736  head_ = item->next.aba_ptr;
737  *msg = p;
738  return 0;
739  }
740  size_t GetListenerCount() const NLIB_NOEXCEPT { return listener_count_; }
741  void SwapUnsafe(LockFreeBroadcastQueueImpl& rhs) NLIB_NOEXCEPT { // NOLINT
742  std::swap(head_, rhs.head_);
743  std::swap(tail_, rhs.tail_);
744  std::swap(listener_count_, rhs.listener_count_);
745  pool_.SwapUnsafe(rhs.pool_);
746  listeners_.swap(rhs.listeners_);
747  }
748 
749  private:
750  uintptr_t Load(uintptr_t* p, int memorder = NLIB_ATOMIC_RELAXED) NLIB_NOEXCEPT {
751  return reinterpret_cast<uintptr_t>(nlib_atomic_loadptr(reinterpret_cast<void**>(p),
752  memorder));
753  }
754 
755  private:
756  uintptr_t head_;
757  uintptr_t tail_;
758  int32_t listener_count_;
759  LockFreePlaceHolderPool<const void*, int32_t> pool_;
760  UniquePtr<uintptr_t[]> listeners_;
761 };
762 
763 } // namespace detail
764 
765 template<class T>
767  public:
768  struct empty_func {
769  void operator()(const T*) {}
770  };
772  LockFreeBroadcastQueue() NLIB_NOEXCEPT : impl_() {}
773  ~LockFreeBroadcastQueue() NLIB_NOEXCEPT {
774  const void* p;
775  while (impl_.DeleteUnsafe(&p) == 0) {
776  DestructorForLockFree<const T>()(reinterpret_cast<const T*>(p));
777  }
778  }
779  // NOT thread safe
780  errno_t Init(size_t max_size, size_t listeners) NLIB_NOEXCEPT {
781  // not thread safe
782  return impl_.Init(max_size, listeners);
783  }
784  errno_t Enqueue(const T* obj) NLIB_NOEXCEPT {
785  // thread safe
786  return impl_.Enqueue(obj);
787  }
788  errno_t Dequeue(int32_t listener_id, DequeueType& obj) NLIB_NOEXCEPT { // NOLINT
789  // thread safe if listener_id is different
790  const void* x;
791  errno_t e = impl_.Dequeue(listener_id, &x);
792  if (e != 0) return e;
793  obj.reset(reinterpret_cast<const T*>(x));
794  const T* p = reinterpret_cast<const T*>(impl_.CheckAndRemove());
795  if (p) {
797  }
798  return 0;
799  }
800  size_t GetListenerCount() const NLIB_NOEXCEPT {
801  // thread safe
802  return impl_.GetListenerCount();
803  }
804  void SwapUnsafe(LockFreeBroadcastQueue& rhs) NLIB_NOEXCEPT { // NOLINT
805  impl_.SwapUnsafe(rhs);
806  }
807 
808  private:
809  detail::LockFreeBroadcastQueueImpl impl_;
810 };
811 
813  public:
814  class MemHolder {
815  public:
816  void* Get() NLIB_NOEXCEPT { return ptr_; }
817 
818  private:
819  void* const ptr_;
821  };
822  LockFreeUnitHeap() NLIB_NOEXCEPT : mem_(), pool_() {}
823  // NOT thread safe
824  NLIB_VIS_PUBLIC errno_t Init(size_t unit_size, size_t align,
825  size_t count) NLIB_NOEXCEPT;
827 
828  // MemHolder* x = heap.Alloc();
829  // void* ptr = x->Get(); // 'ptr' is what you want.
830  NLIB_ALWAYS_INLINE MemHolder* Alloc() NLIB_NOEXCEPT {
831  return reinterpret_cast<MemHolder*>(pool_.Alloc());
832  }
833 
834  NLIB_ALWAYS_INLINE void Free(MemHolder* p) NLIB_NOEXCEPT {
835  pool_.Free(reinterpret_cast<LockFreePlaceHolder<void*>*>(p));
836  }
837 
838  // NOT thread safe
839  // MemHolder* x = heap.Alloc();
840  // void* ptr = x->Get(); // 'ptr' is what you want.
841  NLIB_ALWAYS_INLINE MemHolder* AllocUnsafe() NLIB_NOEXCEPT {
842  return reinterpret_cast<MemHolder*>(pool_.AllocUnsafe());
843  }
844  // NOT thread safe
845  NLIB_ALWAYS_INLINE void FreeUnsafe(MemHolder* p) NLIB_NOEXCEPT {
846  pool_.FreeUnsafe(reinterpret_cast<LockFreePlaceHolder<void*>*>(p));
847  }
848  void SwapUnsafe(LockFreeUnitHeap& rhs) NLIB_NOEXCEPT { // NOLINT
849  using std::swap;
850  swap(mem_, rhs.mem_);
851  pool_.SwapUnsafe(rhs.pool_);
852  }
853 
854  private:
856  LockFreePlaceHolderPool<void*> pool_;
858 };
859 
860 NLIB_NAMESPACE_END
861 
862 #endif // INCLUDE_NN_NLIB_LOCKFREE_H_
void FreeUnsafe(MemHolder *p) noexcept
Free()と同様ですが、スレッドセーフではありません。
Definition: LockFree.h:845
errno_t PopUnsafe(PopType x) noexcept
スタックから要素を取り出してxに格納します。スレッドセーフではありません。
Definition: LockFree.h:482
LockFreePipe() noexcept
デフォルトコンストラクタです。
Definition: LockFree.h:364
int nlib_atomic_compare_exchangeptr(void **ptr, void **expected, void *desired, int weak, int success_memorder, int failure_memorder)
アトミックな値の比較と入れ替えを行います。動作はgccの__atomic_compare_exchange_n()に準じます。 ...
int32_t nlib_atomic_load32(const int32_t *ptr, int memorder)
アトミックに値をロードします。動作はgccの__atomic_load_n()に準じます。
#define NLIB_ALWAYS_INLINE
コンパイラに関数をインライン展開するように強く示します。
Definition: Platform_unix.h:97
LockFreeQueue() noexcept
デフォルトコンストラクタです。
Definition: LockFree.h:545
C++11の標準ヘッダとなるtype_traitsの代用定義です。 コンパイラや標準ライブラリによってサポートされてい...
UniquePtr< const T, empty_func > DequeueType
Dequeue()の引数となる型です
Definition: LockFree.h:771
nlib_mq_msg_destructor destructor
メッセージキューから取り出したメッセージのデストラクタ関数を設定、取得できます。
Definition: Platform.h:1179
errno_t nlib_mq_close(nlib_mq mq)
ハンドルで示されるメッセージキューをクローズします。
#define NLIB_DISALLOW_COPY_AND_ASSIGN(TypeName)
TypeName で指定されたクラスのコピーコンストラクタと代入演算子を禁止します。
Definition: Config.h:179
errno_t nlib_mq_receive(nlib_mq mq, nlib_mq_msg *msg, int *prio)
メッセージをキューから受信します。受信したメッセージはユーザーがデストラクタ関数で削除する必要があり...
errno_t Init(size_t count) noexcept
スタックを初期化します。スレッドセーフではありません。
Definition: LockFree.h:471
T * PopType
Pop(), PopUnsafe()の引数となる型です
Definition: LockFree.h:465
#define NLIB_ATOMIC_RELEASE
gccの__ATOMIC_RELEASEやC++11のstd::memory_order_releaseに準じます。
LockFreeStack() noexcept
デフォルトコンストラクタです。
Definition: LockFree.h:466
~LockFreeQueue() noexcept
デストラクタです。
Definition: LockFree.h:546
#define NLIB_UNLIKELY(x)
条件xが偽になる傾向が高いことをコンパイラに示します。
アラインされたメモリを得るためのクラスです。
errno_t DequeueUnsafe(DequeueType x) noexcept
キューから要素を取り出してxに格納します。スレッドセーフではありません。
Definition: LockFree.h:561
size_t GetBufferSize() noexcept
バッファ・サイズを返します。スレッドセーフです。
Definition: LockFree.h:365
UniquePtrはポインタの所有権を保持し、UniquePtrがスコープから出るときにデストラクタでポインタをDELで指...
Definition: UniquePtr.h:109
errno_t PushUnsafe(const T &x) noexcept
スタックに要素xを積みます。スレッドセーフではありません。
Definition: LockFree.h:480
std::unique_ptrに相当するクラスが定義されています。
errno_t nlib_mq_open(nlib_mq *mq, const nlib_mq_attr *attr)
スレッド間でメッセージをやりとりするためのメッセージキューを作成します。
errno_t Pop(PopType x) noexcept
スタックから要素を取り出してxに格納します。スレッドセーフです。
Definition: LockFree.h:478
errno_t LockFreeInit(T **ptr) noexcept
スレッドセーフにオブジェクトの構築を行います。
Definition: LockFree.h:630
static int nlib_clz32(uint32_t x)
MSB(most significant bit)から見て連続する0ビットの数を返します。
Definition: Platform.h:2615
void SwapUnsafe(LockFreePriorityQueue &rhs) noexcept
オブジェクトをスワップします。スレッドセーフではありません。
Definition: LockFree.h:689
errno_t EnqueueUnsafe(const T &x) noexcept
キューに要素xを追加します。スレッドセーフではありません。
Definition: LockFree.h:559
#define NLIB_VIS_PUBLIC
関数やクラス等のシンボルをライブラリの外部に公開します。
Definition: Platform_unix.h:89
固定メモリサイズの領域を確保・解放をロックフリーで行うことのできるプールアロケータです。 ...
Definition: LockFree.h:812
int32_t max_msg
メッセージキューの作成の際に最大メッセージ数を設定することができます。
Definition: Platform.h:1177
指定された数のリスナーがキューから要素を取得できます。全てのリスナーが取得後、要素はキューから削除さ...
Definition: LockFree.h:766
#define NLIB_ATOMIC_ACQUIRE
gccの__ATOMIC_ACQUIREやC++11のstd::memory_order_acquireに準じます。
MemHolder * AllocUnsafe() noexcept
Alloc()と同様ですが、スレッドセーフではありません。
Definition: LockFree.h:841
errno_t Read(void *dest, size_t nbytes) noexcept
データをパイプから読み込みます。スレッドセーフです。
Definition: LockFree.h:371
int32_t nlib_mq
メッセージキューに関連付けられるハンドルです。ハンドルがゼロクリア(memset()を利用してください)された...
Definition: Platform.h:1161
void * nlib_atomic_loadptr(void *const *ptr, int memorder)
アトミックに値をロードします。動作はgccの__atomic_load_n()に準じます。
void SwapUnsafe(LockFreeStack &rhs) noexcept
オブジェクトをスワップします。スレッドセーフではありません。
Definition: LockFree.h:483
errno_t Enqueue(T *obj, int prio) noexcept
キューに要素を追加します。スレッドセーフです。
Definition: LockFree.h:677
errno_t Enqueue(const T &x) noexcept
キューに要素xを追加します。スレッドセーフです。
Definition: LockFree.h:556
UniquePtr< T, DestructorForLockFree< T > > DequeueType
Dequeue()の引数となる型です
Definition: LockFree.h:652
errno_t Write(const void *src, size_t nbytes) noexcept
データをパイプに書き込みます。スレッドセーフです。
Definition: LockFree.h:402
#define NLIB_LIKELY(x)
条件xが真になる傾向が高いことをコンパイラに示します。
Definition: Platform_unix.h:99
T * DequeueType
Dequeue(), DequeueUnsafe()の引数となる型です
Definition: LockFree.h:544
static errno_t nlib_memcpy(void *s1, size_t s1max, const void *s2, size_t n)
N1078のmemcpy_sに相当する実装です。
Definition: Platform.h:2437
int32_t nlib_atomic_add_fetch32(int32_t *ptr, int32_t val, int memorder)
アトミックな値の加算を行います。動作はgccの__atomic_add_fetch()に準じます。
ロックフリーなスタックを実装しているクラスです。
Definition: LockFree.h:463
void nlib_atomic_storeptr(void **ptr, void *val, int memorder)
アトミックに値をストアします。動作はgccの__atomic_store_n()に準じます。
size_t GetListenerCount() const noexcept
Init()で指定したリスナーの数を返します。スレッドセーフです。
Definition: LockFree.h:800
オブジェクトをデストラクトするためのクラステンプレートです。特殊化して利用します。 ...
Definition: LockFree.h:457
void SwapUnsafe(LockFreeQueue &rhs) noexcept
オブジェクトをスワップします。スレッドセーフではありません。
Definition: LockFree.h:564
void nlib_atomic_thread_fence(int memorder)
指定されたメモリバリアを配置します。
MemHolder * Alloc() noexcept
メモリを割り当てます。スレッドセーフです。
Definition: LockFree.h:830
void SwapUnsafe(LockFreeUnitHeap &rhs) noexcept
オブジェクトをスワップします。スレッドセーフではありません。
Definition: LockFree.h:848
メッセージキューの設定や現在の状態を格納する構造体です。
Definition: Platform.h:1175
ロックフリーなキューを実装しているクラスです。
Definition: LockFree.h:542
#define NLIB_NOEXCEPT
環境に合わせてnoexcept 又は同等の定義がされます。
Definition: Config.h:105
void SwapUnsafe(LockFreeBroadcastQueue &rhs) noexcept
オブジェクトをスワップします。スレッドセーフではありません。
Definition: LockFree.h:804
errno_t Dequeue(DequeueType &obj, int *prio) noexcept
キューから要素を取り出します。スレッドセーフです。
Definition: LockFree.h:681
開発環境別の設定が書かれるファイルです。
errno_t Close() noexcept
キューをクローズし初期化前の状態にします。スレッドセーフではありません。
Definition: LockFree.h:671
errno_t Init(size_t count) noexcept
キューを初期化します。スレッドセーフではありません。
Definition: LockFree.h:550
errno_t Dequeue(DequeueType x) noexcept
キューから要素を取り出してxに格納します。スレッドセーフです。
Definition: LockFree.h:557
アラインされたメモリを得たい場合に利用します。
errno_t Push(const T &x) noexcept
スタックに要素xを積みます。スレッドセーフです。
Definition: LockFree.h:477
errno_t nlib_mq_send(nlib_mq mq, nlib_mq_msg msg, int prio)
メッセージをキューに送信します。
#define NLIB_ATOMIC_RELAXED
gccの__ATOMIC_RELAXEDやC++11のstd::memory_order_relaxedに準じます。
LockFreeUnitHeap() noexcept
デフォルトコンストラクタです。
Definition: LockFree.h:822
errno_t Init(size_t max_size, size_t listeners) noexcept
キューを初期化します。スレッドセーフではありません。
Definition: LockFree.h:780
データの送り手側のスレッドと受け手側のスレッドがそれぞれ1つずつの場合、このクラスを用いてロックフリー...
Definition: LockFree.h:362
#define NLIB_FINAL
利用可能であればfinalが定義されます。そうでない場合は空文字列です。
Definition: Config.h:245
errno_t Init(size_t max_size) noexcept
キューを初期化します。スレッドセーフではありません。
Definition: LockFree.h:660
#define NLIB_STATIC_ASSERT(exp)
静的アサートが定義されます。利用可能であればstatic_assertを利用します。
Definition: Config.h:170
LockFreeBroadcastQueue() noexcept
デフォルトコンストラクタです。
Definition: LockFree.h:772
オブジェクトを初期化するためのクラステンプレートです。特殊化して利用します。
Definition: LockFree.h:451
~LockFreeStack() noexcept
デストラクタです。
Definition: LockFree.h:467
~LockFreeBroadcastQueue() noexcept
デストラクタです。
Definition: LockFree.h:773
errno_t Dequeue(int32_t listener_id, DequeueType &obj) noexcept
リスナーを指定してキューから要素を読み込みます。異なるlistener_idを利用している場合はスレッドセーフで...
Definition: LockFree.h:788
void Free(MemHolder *p) noexcept
メモリを解放します。スレッドセーフです。
Definition: LockFree.h:834
LockFreePriorityQueue() noexcept
デフォルトコンストラクタです。
Definition: LockFree.h:653
#define NLIB_NONNULL
全ての引数にNULLを指定することができないことを示します。
void nlib_atomic_store32(int32_t *ptr, int32_t val, int memorder)
アトミックに値をストアします。動作はgccの__atomic_store_n()に準じます。
int32_t flag
メッセージキューを作成する際の設定です。
Definition: Platform.h:1176
ロックフリーな優先度つきキューを実装したクラスで、nlib_mqをラップしています。
Definition: LockFree.h:650
~LockFreePriorityQueue() noexcept
デストラクタです。
Definition: LockFree.h:656
void * nlib_mq_msg
メッセージキューに格納されるメッセージの型です。
Definition: Platform.h:1167
static int nlib_clz64(uint64_t x)
MSB(most significant bit)から見て連続する0ビットの数を返します。
Definition: Platform.h:2617
errno_t Enqueue(const T *obj) noexcept
キューに要素を追加します。スレッドセーフです。
Definition: LockFree.h:784
int errno_t
intのtypedefで、戻り値としてPOSIXのエラー値を返すことを示します。
Definition: NMalloc.h:37