CppCommon  1.0.4.1
C++ Common Library
barrier.cpp
Go to the documentation of this file.
1 
9 #include "threads/barrier.h"
10 
12 
13 #include <cassert>
14 
15 #if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__)
16 #include "errors/fatal.h"
17 #include <pthread.h>
18 #elif defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__)
19 #include <condition_variable>
20 #include <mutex>
21 #elif defined(_WIN32) || defined(_WIN64)
22 #include <windows.h>
23 #endif
24 
25 namespace CppCommon {
26 
28 
29 class Barrier::Impl
30 {
31 public:
32  explicit Impl(int threads) : _threads(threads)
33  {
34  assert((threads > 0) && "Barrier threads counter must be greater than zero!");
35 
36 #if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__)
37  int result = pthread_barrier_init(&_barrier, nullptr, threads);
38  if (result != 0)
39  throwex SystemException("Failed to initialize a synchronization barrier!", result);
40 #elif defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__)
41  _counter = threads;
42  _generation = 0;
43 #elif defined(_WIN32) || defined(_WIN64)
44  if (!InitializeSynchronizationBarrier(&_barrier, threads, -1))
45  throwex SystemException("Failed to initialize a synchronization barrier!");
46 #endif
47  }
48 
49  ~Impl()
50  {
51 #if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__)
52  int result = pthread_barrier_destroy(&_barrier);
53  if (result != 0)
54  fatality(SystemException("Failed to destroy a synchronization barrier!", result));
55 #elif defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__)
56  // Do nothing here...
57 #elif defined(_WIN32) || defined(_WIN64)
58  DeleteSynchronizationBarrier(&_barrier);
59 #endif
60  }
61 
62  int threads() const noexcept
63  {
64  return _threads;
65  }
66 
67  bool Wait()
68  {
69 #if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__)
70  int result = pthread_barrier_wait(&_barrier);
71  if ((result != PTHREAD_BARRIER_SERIAL_THREAD) && (result != 0))
72  throwex SystemException("Failed to wait at a synchronization barrier!", result);
73  return (result == PTHREAD_BARRIER_SERIAL_THREAD);
74 #elif defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__)
75  std::unique_lock<std::mutex> lock(_mutex);
76 
77  // Remember the current barrier generation
78  int generation = _generation;
79 
80  // Decrease the count of waiting threads
81  if (--_counter == 0)
82  {
83  // Increase the current barrier generation
84  ++_generation;
85 
86  // Reset waiting threads counter
87  _counter = _threads;
88 
89  // Notify all waiting threads
90  _cond.notify_all();
91 
92  // Notify the last thread that reached the barrier
93  return true;
94  }
95 
96  // Wait for the next barrier generation
97  _cond.wait(lock, [&, this]() { return generation != _generation; });
98 
99  // Notify each of remaining threads
100  return false;
101 #elif defined(_WIN32) || defined(_WIN64)
102  return (EnterSynchronizationBarrier(&_barrier, 0) == TRUE);
103 #endif
104  }
105 
106 private:
107  int _threads;
108 #if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__)
109  pthread_barrier_t _barrier;
110 #elif defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__)
111  std::mutex _mutex;
112  std::condition_variable _cond;
113  int _counter;
114  int _generation;
115 #elif defined(_WIN32) || defined(_WIN64)
116  SYNCHRONIZATION_BARRIER _barrier;
117 #endif
118 };
119 
121 
122 Barrier::Barrier(int threads)
123 {
124  // Check implementation storage parameters
125  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
126  static_assert((StorageSize >= sizeof(Impl)), "Barrier::StorageSize must be increased!");
127  static_assert(((StorageAlign % alignof(Impl)) == 0), "Barrier::StorageAlign must be adjusted!");
128 
129  // Create the implementation instance
130  new(&_storage)Impl(threads);
131 }
132 
134 {
135  // Delete the implementation instance
136  reinterpret_cast<Impl*>(&_storage)->~Impl();
137 }
138 
139 int Barrier::threads() const noexcept { return impl().threads(); }
140 
141 bool Barrier::Wait() { return impl().Wait(); }
142 
143 } // namespace CppCommon
Barrier synchronization primitive definition.
int threads() const noexcept
Get the count of threads to wait at the barrier.
Definition: barrier.cpp:139
Barrier(int threads)
Default class constructor.
Definition: barrier.cpp:122
bool Wait()
Wait at the barrier until all other threads reach this barrier.
Definition: barrier.cpp:141
#define throwex
Throw extended exception macro.
Definition: exceptions.h:23
Fatal abort execution definition.
#define fatality(...)
Fatal abort execution extended macro.
Definition: fatal.h:22
C++ Common project definitions.
Definition: token_bucket.h:15
Aligned storage validator definition.