CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
named_condition_variable.cpp
Go to the documentation of this file.
1
10
11#include "errors/fatal.h"
13
14#include <algorithm>
15
16#if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__) && !defined(__CYGWIN__)
17#include "system/shared_type.h"
18#include <pthread.h>
19#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
20#include "system/shared_type.h"
21#include <windows.h>
22#undef max
23#undef min
24#endif
25
26namespace CppCommon {
27
29
30class NamedConditionVariable::Impl
31{
32public:
33 Impl(const std::string& name) : _name(name)
34#if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__) && !defined(__CYGWIN__)
35 , _shared(name)
36#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
37 , _shared(name)
38#endif
39 {
40#if defined(__APPLE__)
41 throwex SystemException("Named condition variable is not supported!");
42#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
43 // Only the owner should initializate a named condition variable
44 if (_shared.owner())
45 {
46 pthread_mutexattr_t mutex_attribute;
47 int result = pthread_mutexattr_init(&mutex_attribute);
48 if (result != 0)
49 throwex SystemException("Failed to initialize a mutex attribute for the named condition variable!", result);
50 result = pthread_mutexattr_setpshared(&mutex_attribute, PTHREAD_PROCESS_SHARED);
51 if (result != 0)
52 throwex SystemException("Failed to set a mutex process shared attribute for the named condition variable!", result);
53 result = pthread_mutex_init(&_shared->mutex, &mutex_attribute);
54 if (result != 0)
55 throwex SystemException("Failed to initialize a mutex for the named condition variable!", result);
56 result = pthread_mutexattr_destroy(&mutex_attribute);
57 if (result != 0)
58 throwex SystemException("Failed to destroy a mutex attribute for the named condition variable!", result);
59
60 pthread_condattr_t cond_attribute;
61 result = pthread_condattr_init(&cond_attribute);
62 if (result != 0)
63 throwex SystemException("Failed to initialize a conditional variable attribute for the named condition variable!", result);
64 result = pthread_condattr_setpshared(&cond_attribute, PTHREAD_PROCESS_SHARED);
65 if (result != 0)
66 throwex SystemException("Failed to set a conditional variable process shared attribute for the named condition variable!", result);
67 result = pthread_cond_init(&_shared->cond, &cond_attribute);
68 if (result != 0)
69 throwex SystemException("Failed to initialize a conditional variable for the named condition variable!", result);
70 result = pthread_condattr_destroy(&cond_attribute);
71 if (result != 0)
72 throwex SystemException("Failed to destroy a conditional variable attribute for the named condition variable!", result);
73 }
74#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
75 // Owner of the condition variable should initialize its value
76 if (_shared.owner())
77 *_shared = 0;
78 _mutex = CreateMutexA(nullptr, FALSE, (name + "-mutex").c_str());
79 if (_mutex == nullptr)
80 throwex SystemException("Failed to create or open a named mutex for the named condition variable!");
81 _semaphore = CreateSemaphoreA(nullptr, 0, std::numeric_limits<LONG>::max(), (name + "-semaphore").c_str());
82 if (_semaphore == nullptr)
83 throwex SystemException("Failed to create or open a named semaphore for the named condition variable!");
84#endif
85 }
86
87 ~Impl()
88 {
89#if defined(__APPLE__)
90 fatality(SystemException("Named condition variable is not supported!"));
91#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
92 // Only the owner should destroy a named condition variable
93 if (_shared.owner())
94 {
95 int result = pthread_mutex_destroy(&_shared->mutex);
96 if (result != 0)
97 fatality(SystemException("Failed to destroy a mutex for the named condition variable!", result));
98 result = pthread_cond_destroy(&_shared->cond);
99 if (result != 0)
100 fatality(SystemException("Failed to destroy a conditional variable for the named condition variable!", result));
101 }
102#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
103 if (!CloseHandle(_mutex))
104 fatality(SystemException("Failed to close a named mutex for the named condition variable!"));
105 if (!CloseHandle(_semaphore))
106 fatality(SystemException("Failed to close a named semaphore for the named condition variable!"));
107#endif
108 }
109
110 const std::string& name() const
111 {
112 return _name;
113 }
114
115 void NotifyOne()
116 {
117#if defined(__APPLE__)
118 throwex SystemException("Named condition variable is not supported!");
119#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
120 int result = pthread_cond_signal(&_shared->cond);
121 if (result != 0)
122 throwex SystemException("Failed to signal a named condition variable!", result);
123#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
124 // Lock the named mutex
125 DWORD result = WaitForSingleObject(_mutex, INFINITE);
126 if (result != WAIT_OBJECT_0)
127 throwex SystemException("Failed to lock a named mutex for the named condition variable!");
128 // Decrement shared waiters count
129 --(*_shared);
130 // Signal one waiter
131 if (!ReleaseSemaphore(_semaphore, 1, nullptr))
132 throwex SystemException("Failed to release one semaphore waiter for the named condition variable!");
133 // Unlock the named mutex
134 if (!ReleaseMutex(_mutex))
135 throwex SystemException("Failed to unlock a named mutex for the named condition variable!");
136#endif
137 }
138
139 void NotifyAll()
140 {
141#if defined(__APPLE__)
142 throwex SystemException("Named condition variable is not supported!");
143#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
144 int result = pthread_cond_broadcast(&_shared->cond);
145 if (result != 0)
146 throwex SystemException("Failed to broadcast a named condition variable!", result);
147#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
148 // Lock the named mutex
149 DWORD result = WaitForSingleObject(_mutex, INFINITE);
150 if (result != WAIT_OBJECT_0)
151 throwex SystemException("Failed to lock a named mutex for the named condition variable!");
152 // Signal all waiters
153 if (!ReleaseSemaphore(_semaphore, *_shared, nullptr))
154 throwex SystemException("Failed to release all semaphore waiters for the named condition variable!");
155 // Clear all shared waiters
156 *_shared = 0;
157 // Unlock the named mutex
158 if (!ReleaseMutex(_mutex))
159 throwex SystemException("Failed to unlock a named mutex for the named condition variable!");
160#endif
161 }
162
163 void Wait()
164 {
165#if defined(__APPLE__)
166 throwex SystemException("Named condition variable is not supported!");
167#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
168 int result = pthread_cond_wait(&_shared->cond, &_shared->mutex);
169 if (result != 0)
170 throwex SystemException("Failed to waiting a named condition variable!", result);
171#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
172 // Lock the named mutex
173 DWORD result = WaitForSingleObject(_mutex, INFINITE);
174 if (result != WAIT_OBJECT_0)
175 throwex SystemException("Failed to lock a named mutex for the named condition variable!");
176 // Increment shared waiters count
177 ++(*_shared);
178 // Unlock the named mutex
179 if (!ReleaseMutex(_mutex))
180 throwex SystemException("Failed to unlock a named mutex for the named condition variable!");
181
182 // Wait for the named condition variable
183 result = WaitForSingleObject(_semaphore, INFINITE);
184 if (result != WAIT_OBJECT_0)
185 throwex SystemException("Failed to wait a named condition variable!");
186#endif
187 }
188
189 bool TryWaitFor(const Timespan& timespan)
190 {
191 if (timespan < 0)
192 return false;
193#if defined(__APPLE__)
194 throwex SystemException("Named condition variable is not supported!");
195#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
196 struct timespec timeout;
197 timeout.tv_sec = timespan.seconds();
198 timeout.tv_nsec = timespan.nanoseconds() % 1000000000;
199 int result = pthread_cond_timedwait(&_shared->cond, &_shared->mutex, &timeout);
200 if ((result != 0) && (result != ETIMEDOUT))
201 throwex SystemException("Failed to waiting a named condition variable for the given timeout!", result);
202 return (result == 0);
203#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
204 // Lock the named mutex
205 DWORD result = WaitForSingleObject(_mutex, INFINITE);
206 if (result != WAIT_OBJECT_0)
207 throwex SystemException("Failed to lock a named mutex for the named condition variable!");
208 // Increment shared waiters count
209 ++(*_shared);
210 // Unlock the named mutex
211 if (!ReleaseMutex(_mutex))
212 throwex SystemException("Failed to unlock a named mutex for the named condition variable!");
213
214 // Wait for the named condition variable
215 result = WaitForSingleObject(_semaphore, std::max((DWORD)0, (DWORD)timespan.milliseconds()));
216 if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
217 throwex SystemException("Failed to try lock a named condition variable for the given timeout!");
218 return (result == WAIT_OBJECT_0);
219#endif
220 }
221
222private:
223 std::string _name;
224#if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__) && !defined(__CYGWIN__)
225 // Shared condition variable structure
226 struct CondVar
227 {
228 pthread_mutex_t mutex;
229 pthread_cond_t cond;
230 };
231
232 // Shared condition variable structure wrapper
233 SharedType<CondVar> _shared;
234#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
235 HANDLE _mutex;
236 HANDLE _semaphore;
237 SharedType<LONG> _shared;
238#endif
239};
240
242
244{
245 // Check implementation storage parameters
246 [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
247 static_assert((StorageSize >= sizeof(Impl)), "NamedConditionVariable::StorageSize must be increased!");
248 static_assert(((StorageAlign % alignof(Impl)) == 0), "NamedConditionVariable::StorageAlign must be adjusted!");
249
250 // Create the implementation instance
251 new(&_storage)Impl(name);
252}
253
255{
256 // Delete the implementation instance
257 reinterpret_cast<Impl*>(&_storage)->~Impl();
258}
259
260const std::string& NamedConditionVariable::name() const { return impl().name(); }
261
262void NamedConditionVariable::NotifyOne() { impl().NotifyOne(); }
263void NamedConditionVariable::NotifyAll() { impl().NotifyAll(); }
264
265void NamedConditionVariable::Wait() { impl().Wait(); }
266
267bool NamedConditionVariable::TryWaitFor(const Timespan& timespan) { return impl().TryWaitFor(timespan); }
268
269} // namespace CppCommon
void NotifyOne()
Notify one of waiting thread about event occurred.
void NotifyAll()
Notify all waiting threads about event occurred.
NamedConditionVariable(const std::string &name)
Default class constructor.
const std::string & name() const
Get the condition variable name.
void Wait()
Wait until condition variable is notified.
bool TryWaitFor(const Timespan &timespan)
Try to wait for the given timespan until condition variable is notified.
#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
Named condition variable synchronization primitive definition.
C++ Common project definitions.
Shared memory type definition.
Aligned storage validator definition.