Pioneer
Semaphore.h
Go to the documentation of this file.
1 //---------------------------------------------------------
2 // Heavily adapted version of:
3 // sema.h - C++11 On Multicore
4 // Copyright (c) 2015 Jeff Preshing
5 // Released under the zlib License
6 // For conditions of distribution and use, see
7 // https://github.com/preshing/cpp11-on-multicore/blob/master/LICENSE
8 //---------------------------------------------------------
9 
10 #pragma once
11 
12 #include "SDL_mutex.h"
13 #include <atomic_queue/defs.h>
14 
15 // Lightweight spinlock semaphore
16 class Semaphore {
17 public:
18  Semaphore(uint32_t initialCount = 0) :
19  m_sem(SDL_CreateSemaphore(0)),
20  m_count(initialCount)
21  {}
22 
24  {
25  SDL_DestroySemaphore(m_sem);
26  }
27 
28  // return the number of waiting threads
29  int32_t count() const { return -m_count.load(std::memory_order_acquire); }
30 
31  bool try_wait()
32  {
33  int value = m_count.load(std::memory_order_relaxed);
34  return (value > 0 && m_count.compare_exchange_strong(value, value - 1, std::memory_order_acquire));
35  }
36 
37  void wait()
38  {
39  if (!try_wait())
40  wait_with_spinlock();
41  }
42 
43  // immediately wait without spinning if the semaphore is not signalled
44  void waitonly()
45  {
46  if (!try_wait()) {
47  int value = m_count.fetch_sub(1, std::memory_order_acquire);
48  if (value <= 0)
49  SDL_SemWait(m_sem);
50  }
51  }
52 
53  void signal(int count = 1)
54  {
55  int value = m_count.fetch_add(count, std::memory_order_release);
56  int toRelease = -value < count ? -value : count;
57  while (toRelease-- > 0) {
58  SDL_SemPost(m_sem);
59  }
60  }
61 
62 private:
63  void wait_with_spinlock()
64  {
65  uint32_t spinCount = 1000;
66  int32_t value = 0;
67 
68  while (spinCount--) {
69  value = m_count.load(std::memory_order_relaxed);
70  if ((value > 0) && m_count.compare_exchange_strong(value, value - 1, std::memory_order_acquire))
71  return;
72  atomic_queue::spin_loop_pause();
73  // keep the compiler from detrimentally optimizing the loop
74  std::atomic_signal_fence(std::memory_order_acquire);
75  }
76 
77  value = m_count.fetch_sub(1, std::memory_order_acquire);
78  if (value <= 0)
79  SDL_SemWait(m_sem);
80  }
81 
82  SDL_semaphore *m_sem;
83  std::atomic<int32_t> m_count;
84 };
Definition: Semaphore.h:16
void signal(int count=1)
Definition: Semaphore.h:53
int32_t count() const
Definition: Semaphore.h:29
void waitonly()
Definition: Semaphore.h:44
Semaphore(uint32_t initialCount=0)
Definition: Semaphore.h:18
~Semaphore()
Definition: Semaphore.h:23
void wait()
Definition: Semaphore.h:37
bool try_wait()
Definition: Semaphore.h:31