CppCommon  1.0.4.1
C++ Common Library
condition_variable.cpp
Go to the documentation of this file.
1 
10 
12 
13 #include <algorithm>
14 
15 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
16 #include "errors/fatal.h"
17 #include <pthread.h>
18 #elif defined(_WIN32) || defined(_WIN64)
19 #include <windows.h>
20 #undef max
21 #undef min
22 #endif
23 
24 namespace CppCommon {
25 
27 
28 class ConditionVariable::Impl
29 {
30 public:
31  Impl()
32  {
33 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
34  int result = pthread_cond_init(&_cond, nullptr);
35  if (result != 0)
36  throwex SystemException("Failed to initialize a condition variable!", result);
37 #elif defined(_WIN32) || defined(_WIN64)
38  InitializeConditionVariable(&_cond);
39 #endif
40  }
41 
42  ~Impl()
43  {
44 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
45  int result = pthread_cond_destroy(&_cond);
46  if (result != 0)
47  fatality(SystemException("Failed to destroy a condition variable!", result));
48 #elif defined(_WIN32) || defined(_WIN64)
49  // Condition variables do not need to be explicitly destroyed.
50 #endif
51  }
52 
53  void NotifyOne()
54  {
55 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
56  int result = pthread_cond_signal(&_cond);
57  if (result != 0)
58  throwex SystemException("Failed to signal a condition variable!", result);
59 #elif defined(_WIN32) || defined(_WIN64)
60  WakeConditionVariable(&_cond);
61 #endif
62  }
63 
64  void NotifyAll()
65  {
66 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
67  int result = pthread_cond_broadcast(&_cond);
68  if (result != 0)
69  throwex SystemException("Failed to broadcast a condition variable!", result);
70 #elif defined(_WIN32) || defined(_WIN64)
71  WakeAllConditionVariable(&_cond);
72 #endif
73  }
74 
75  void Wait(CriticalSection& cs)
76  {
77 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
78  int result = pthread_cond_wait(&_cond, (pthread_mutex_t*)cs.native());
79  if (result != 0)
80  throwex SystemException("Failed to waiting a condition variable!", result);
81 #elif defined(_WIN32) || defined(_WIN64)
82  if (!SleepConditionVariableCS(&_cond, (CRITICAL_SECTION*)cs.native(), INFINITE))
83  throwex SystemException("Failed to waiting a condition variable!");
84 #endif
85  }
86 
87  bool TryWaitFor(CriticalSection& cs, const Timespan& timespan)
88  {
89  if (timespan < 0)
90  return false;
91 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
92  struct timespec timeout;
93  timeout.tv_sec = timespan.seconds();
94  timeout.tv_nsec = timespan.nanoseconds() % 1000000000;
95  int result = pthread_cond_timedwait(&_cond, (pthread_mutex_t*)cs.native(), &timeout);
96  if ((result != 0) && (result != ETIMEDOUT))
97  throwex SystemException("Failed to waiting a condition variable for the given timeout!", result);
98  return (result == 0);
99 #elif defined(_WIN32) || defined(_WIN64)
100  if (!SleepConditionVariableCS(&_cond, (CRITICAL_SECTION*)cs.native(), std::max((DWORD)0, (DWORD)timespan.milliseconds())))
101  {
102  if (GetLastError() != ERROR_TIMEOUT)
103  throwex SystemException("Failed to waiting a condition variable for the given timeout!");
104  return false;
105  }
106  return true;
107 #endif
108  }
109 
110 private:
111 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
112  pthread_cond_t _cond;
113 #elif defined(_WIN32) || defined(_WIN64)
114  CONDITION_VARIABLE _cond;
115 #endif
116 };
117 
119 
121 {
122  // Check implementation storage parameters
123  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
124  static_assert((StorageSize >= sizeof(Impl)), "ConditionVariable::StorageSize must be increased!");
125  static_assert(((StorageAlign % alignof(Impl)) == 0), "ConditionVariable::StorageAlign must be adjusted!");
126 
127  // Create the implementation instance
128  new(&_storage)Impl();
129 }
130 
132 {
133  // Delete the implementation instance
134  reinterpret_cast<Impl*>(&_storage)->~Impl();
135 }
136 
137 void ConditionVariable::NotifyOne() { impl().NotifyOne(); }
138 void ConditionVariable::NotifyAll() { impl().NotifyAll(); }
139 
140 void ConditionVariable::Wait(CriticalSection& cs) { impl().Wait(cs); }
141 
142 bool ConditionVariable::TryWaitFor(CriticalSection& cs, const Timespan& timespan) { return impl().TryWaitFor(cs, timespan); }
143 
144 } // namespace CppCommon
bool TryWaitFor(CriticalSection &cs, const Timespan &timespan)
Try to wait for the given timespan until condition variable is notified.
void Wait(CriticalSection &cs)
Wait until condition variable is notified.
void NotifyOne()
Notify one of waiting thread about event occurred.
void NotifyAll()
Notify all waiting threads about event occurred.
Critical section synchronization primitive.
Condition variable synchronization primitive definition.
#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.