ORIGINAL
Loading...
Searching...
No Matches
condition.h
Go to the documentation of this file.
1#ifndef CONDITION_H
2#define CONDITION_H
3
4#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
5#include <pthread.h>
6#elif ORIGINAL_COMPILER_MSVC
7#endif
8
9#include "mutex.h"
10#include "zeit.h"
11
29namespace original
30{
44 {
45 public:
47 explicit conditionBase() = default;
48
55 virtual void wait(mutexBase& mutex) = 0;
56
65 virtual bool waitFor(mutexBase& mutex, time::duration d) = 0;
66
75 template<typename Pred>
76 void wait(mutexBase& mutex, Pred predicate) noexcept(noexcept(predicate()));
77
87 template<typename Pred>
88 bool waitFor(mutexBase& mutex, const time::duration& d, Pred predicate) noexcept(noexcept(predicate()));
89
94 virtual void notify() = 0;
95
100 virtual void notifyAll() = 0;
101
115 void notifySome(u_integer n);
116
118 virtual ~conditionBase() = default;
119
121 conditionBase(const conditionBase&) = delete;
122
125 };
126
127#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
135 class pCondition final : public conditionBase
136 {
137 pthread_cond_t cond_;
138
139 public:
140 // Inherit template methods from conditionBase
143
148 explicit pCondition();
149
156 void wait(mutexBase& mutex) override;
157
166 bool waitFor(mutexBase& mutex, time::duration d) override;
167
172 void notify() override;
173
178 void notifyAll() override;
179
184 ~pCondition() override;
185 };
186
187#elif ORIGINAL_COMPILER_MSVC
188 class wCondition final : public conditionBase
189 {
190 CONDITION_VARIABLE cond_;
191 public:
194
195 explicit wCondition();
196
197 void wait(mutexBase& mutex) override;
198
199 bool waitFor(mutexBase& mutex, time::duration d) override;
200
201 void notify() override;
202
203 void notifyAll() override;
204
205 ~wCondition() override;
206 };
207#endif
208
210 #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
211 pCondition cond_;
212 #elif ORIGINAL_COMPILER_MSVC
213 wCondition cond_;
214 #endif
215
216 public:
219
220 condition();
221
222 void wait(mutexBase& mutex) override;
223
224 bool waitFor(mutexBase& mutex, time::duration d) override;
225
226 void notify() override;
227
228 void notifyAll() override;
229 };
230
231}
232template<typename Pred>
234 while (!predicate()){
235 this->wait(mutex);
236 }
237}
238
239template<typename Pred>
241 const time::point start = time::point::now();
242 while (!predicate()) {
243 auto elapsed = time::point::now() - start;
244 if (elapsed >= d)
245 return false;
246 if (!this->waitFor(mutex, d - elapsed))
247 return false;
248 if (predicate())
249 return true;
250 }
251 return true;
252}
253
255 if (n == 0){
256 return;
257 }
258 if (n == 1){
259 this->notify();
260 } else {
261 this->notifyAll();
262 }
263}
264
265#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
266inline original::pCondition::pCondition() : cond_{}
267{
268 if (const int code = pthread_cond_init(&this->cond_, nullptr); code != 0)
269 {
270 throw sysError("Failed to initialize condition variable (pthread_cond_init returned " + printable::formatString(code) + ")");
271 }
272}
273
274inline void original::pCondition::wait(mutexBase& mutex)
275{
276 staticError<valueError, !std::is_same_v<mutex::native_handle, pMutex::native_handle>>::asserts();
277
278 const auto handle = static_cast<mutex::native_handle*>(mutex.nativeHandle());
279 if (const int code = pthread_cond_wait(&this->cond_, handle); code != 0) {
280 throw sysError("Failed to wait on condition variable (pthread_cond_wait returned " + printable::formatString(code) + ")");
281 }
282}
283
284inline bool original::pCondition::waitFor(mutexBase& mutex, const time::duration d)
285{
286 staticError<valueError, !std::is_same_v<mutex::native_handle, pMutex::native_handle>>::asserts();
287
288 const auto deadline = time::point::now() + d;
289 const auto ts = deadline.toTimespec();
290 const auto handle = static_cast<mutex::native_handle*>(mutex.nativeHandle());
291 const int code = pthread_cond_timedwait(&this->cond_, handle, &ts);
292 if (code == 0) return true;
293 if (code == ETIMEDOUT) return false;
294 throw sysError("Failed to timed wait on condition variable (pthread_cond_timed-wait returned " + printable::formatString(code) + ")");
295}
296
297inline void original::pCondition::notify()
298{
299 if (const int code = pthread_cond_signal(&this->cond_); code != 0) {
300 throw sysError("Failed to signal condition variable (pthread_cond_signal returned " + printable::formatString(code) + ")");
301 }
302}
303
304inline void original::pCondition::notifyAll()
305{
306 if (const int code = pthread_cond_broadcast(&this->cond_); code != 0) {
307 throw sysError("Failed to broadcast condition variable (pthread_cond_broadcast returned " + printable::formatString(code) + ")");
308 }
309}
310
311inline original::pCondition::~pCondition()
312{
313 if (const int code = pthread_cond_destroy(&this->cond_); code != 0) {
314 std::cerr << "Warning: Failed to destroy condition variable (pthread_cond_destroy returned "
315 << code << ")" << std::endl;
316 }
317}
318#elif ORIGINAL_COMPILER_MSVC
319inline original::wCondition::wCondition() : cond_{}
320{
321 InitializeConditionVariable(&this->cond_);
322}
323
324inline void original::wCondition::wait(mutexBase& mutex)
325{
326 if (const auto handle = static_cast<mutex::native_handle*>(mutex.nativeHandle());
327 !SleepConditionVariableSRW(&this->cond_, handle, INFINITE, 0)) {
328 throw sysError("Failed to wait on condition variable (SleepConditionVariableSRW returned error " +
329 printable::formatString(GetLastError()));
330 }
331}
332
333inline bool original::wCondition::waitFor(mutexBase& mutex, const time::duration d)
334{
335 const auto handle = static_cast<mutex::native_handle*>(mutex.nativeHandle());
336 if (const auto timeout_ms = d.toDWMilliseconds();
337 !SleepConditionVariableSRW(&this->cond_, handle, timeout_ms, 0)) {
338 const DWORD error = GetLastError();
339 if (error == ERROR_TIMEOUT) {
340 return false;
341 }
342 throw sysError("Failed to timed wait on condition variable (SleepConditionVariableSRW returned error " +
344 }
345 return true;
346}
347
348inline void original::wCondition::notify()
349{
350 WakeConditionVariable(&this->cond_);
351}
352
353inline void original::wCondition::notifyAll()
354{
355 WakeAllConditionVariable(&this->cond_);
356}
357
358inline original::wCondition::~wCondition() = default;
359#endif
360
361inline original::condition::condition() = default;
362
364{
365 this->cond_.wait(mutex);
366}
367
369{
370 return this->cond_.waitFor(mutex, d);
371}
372
374{
375 this->cond_.notify();
376}
377
379{
380 this->cond_.notifyAll();
381}
382
383#endif //CONDITION_H
Abstract base class for condition variable implementations.
Definition condition.h:44
virtual void notifyAll()=0
Notifies all waiting threads.
conditionBase & operator=(const conditionBase &)=delete
Deleted copy assignment operator.
virtual void wait(mutexBase &mutex)=0
Waits for notification while holding the mutex.
conditionBase(const conditionBase &)=delete
Deleted copy constructor.
virtual bool waitFor(mutexBase &mutex, time::duration d)=0
Waits for notification with timeout.
void notifySome(u_integer n)
Notifies a specified number of waiting threads.
Definition condition.h:254
virtual ~conditionBase()=default
Virtual destructor.
conditionBase()=default
Default constructor.
virtual void notify()=0
Notifies one waiting thread.
Definition condition.h:209
void wait(mutexBase &mutex) override
Waits for notification while holding the mutex.
Definition condition.h:363
bool waitFor(mutexBase &mutex, time::duration d) override
Waits for notification with timeout.
Definition condition.h:368
void notifyAll() override
Notifies all waiting threads.
Definition condition.h:378
void notify() override
Notifies one waiting thread.
Definition condition.h:373
Abstract base class for mutex implementations.
Definition mutex.h:37
Definition mutex.h:241
Unique ownership smart pointer with move semantics.
Definition ownerPtr.h:37
static std::string formatString(const TYPE &t)
Universal value-to-string conversion with type-specific formatting.
Definition printable.h:339
Exception for generic system failure.
Definition error.h:413
Represents a time duration with nanosecond precision.
Definition zeit.h:143
Represents a point in time with nanosecond precision.
Definition zeit.h:389
static point now()
Gets current time point.
Definition zeit.h:1386
Cross-platform mutex and lock management utilities.
Main namespace for the project Original.
Definition algorithms.h:21
Time and date handling utilities.