19 struct _SECURITY_ATTRIBUTES;
20 __declspec(dllimport)
void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes,
long lInitialCount,
long lMaximumCount,
const wchar_t* lpName);
21 __declspec(dllimport)
int __stdcall CloseHandle(
void* hObject);
22 __declspec(dllimport)
unsigned long __stdcall WaitForSingleObject(
void* hHandle,
unsigned long dwMilliseconds);
23 __declspec(dllimport)
int __stdcall ReleaseSemaphore(
void* hSemaphore,
long lReleaseCount,
long* lpPreviousCount);
25#elif defined(__MACH__)
27#elif defined(__unix__)
63 Semaphore(
const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
64 Semaphore& operator=(
const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
67 Semaphore(
int initialCount = 0)
69 assert(initialCount >= 0);
70 const long maxLong = 0x7fffffff;
71 m_hSema = CreateSemaphoreW(
nullptr, initialCount, maxLong,
nullptr);
82 const unsigned long infinite = 0xffffffff;
83 return WaitForSingleObject(m_hSema, infinite) == 0;
88 return WaitForSingleObject(m_hSema, 0) == 0;
91 bool timed_wait(std::uint64_t usecs)
93 return WaitForSingleObject(m_hSema, (
unsigned long)(usecs / 1000)) == 0;
96 void signal(
int count = 1)
98 while (!ReleaseSemaphore(m_hSema, count,
nullptr));
101#elif defined(__MACH__)
111 Semaphore(
const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
112 Semaphore& operator=(
const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
115 Semaphore(
int initialCount = 0)
117 assert(initialCount >= 0);
118 kern_return_t rc = semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount);
119 assert(rc == KERN_SUCCESS);
125 semaphore_destroy(mach_task_self(), m_sema);
130 return semaphore_wait(m_sema) == KERN_SUCCESS;
135 return timed_wait(0);
138 bool timed_wait(std::uint64_t timeout_usecs)
141 ts.tv_sec =
static_cast<unsigned int>(timeout_usecs / 1000000);
142 ts.tv_nsec =
static_cast<int>((timeout_usecs % 1000000) * 1000);
145 kern_return_t rc = semaphore_timedwait(m_sema, ts);
146 return rc == KERN_SUCCESS;
151 while (semaphore_signal(m_sema) != KERN_SUCCESS);
154 void signal(
int count)
158 while (semaphore_signal(m_sema) != KERN_SUCCESS);
162#elif defined(__unix__)
171 Semaphore(
const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
172 Semaphore& operator=(
const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
175 Semaphore(
int initialCount = 0)
177 assert(initialCount >= 0);
178 int rc = sem_init(&m_sema, 0,
static_cast<unsigned int>(initialCount));
185 sem_destroy(&m_sema);
193 rc = sem_wait(&m_sema);
194 }
while (rc == -1 && errno == EINTR);
202 rc = sem_trywait(&m_sema);
203 }
while (rc == -1 && errno == EINTR);
207 bool timed_wait(std::uint64_t usecs)
210 const int usecs_in_1_sec = 1000000;
211 const int nsecs_in_1_sec = 1000000000;
212 clock_gettime(CLOCK_REALTIME, &ts);
213 ts.tv_sec += (time_t)(usecs / usecs_in_1_sec);
214 ts.tv_nsec += (long)(usecs % usecs_in_1_sec) * 1000;
217 if (ts.tv_nsec >= nsecs_in_1_sec) {
218 ts.tv_nsec -= nsecs_in_1_sec;
224 rc = sem_timedwait(&m_sema, &ts);
225 }
while (rc == -1 && errno == EINTR);
231 while (sem_post(&m_sema) == -1);
234 void signal(
int count)
238 while (sem_post(&m_sema) == -1);
243#error Unsupported platform! (No semaphore wrapper available)
255 typedef std::make_signed<std::size_t>::type ssize_t;
258 std::atomic<ssize_t> m_count;
259 details::Semaphore m_sema;
262 bool waitWithPartialSpinning(std::int64_t
timeout_usecs = -1)
265 int spin = m_maxSpins;
268 oldCount = m_count.load(std::memory_order_relaxed);
269 if ((
oldCount > 0) && m_count.compare_exchange_strong(
oldCount,
oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed))
271 std::atomic_signal_fence(std::memory_order_acquire);
273 oldCount = m_count.fetch_sub(1, std::memory_order_acquire);
290 oldCount = m_count.load(std::memory_order_acquire);
291 if (
oldCount >= 0 && m_sema.try_wait())
293 if (
oldCount < 0 && m_count.compare_exchange_strong(
oldCount,
oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed))
298 ssize_t waitManyWithPartialSpinning(ssize_t max, std::int64_t
timeout_usecs = -1)
302 int spin = m_maxSpins;
305 oldCount = m_count.load(std::memory_order_relaxed);
309 if (m_count.compare_exchange_strong(
oldCount,
newCount, std::memory_order_acquire, std::memory_order_relaxed))
312 std::atomic_signal_fence(std::memory_order_acquire);
314 oldCount = m_count.fetch_sub(1, std::memory_order_acquire);
321 oldCount = m_count.load(std::memory_order_acquire);
322 if (
oldCount >= 0 && m_sema.try_wait())
324 if (
oldCount < 0 && m_count.compare_exchange_strong(
oldCount,
oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed))
330 return 1 + tryWaitMany(max - 1);
343 ssize_t
oldCount = m_count.load(std::memory_order_relaxed);
346 if (m_count.compare_exchange_weak(
oldCount,
oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed))
354 return tryWait() || waitWithPartialSpinning();
363 ssize_t tryWaitMany(ssize_t max)
366 ssize_t
oldCount = m_count.load(std::memory_order_relaxed);
370 if (m_count.compare_exchange_weak(
oldCount,
newCount, std::memory_order_acquire, std::memory_order_relaxed))
380 ssize_t result = tryWaitMany(max);
381 if (result == 0 && max > 0)
386 ssize_t waitMany(ssize_t max)
388 ssize_t result = waitMany(max, -1);
393 void signal(ssize_t count = 1)
396 ssize_t
oldCount = m_count.fetch_add(count, std::memory_order_release);
404 std::size_t availableApprox()
const
406 ssize_t count = m_count.load(std::memory_order_relaxed);
407 return count > 0 ?
static_cast<std::size_t
>(count) : 0;
Definition concurrentqueue.h:747
Definition lightweightsemaphore.h:253