ChimeraTK-cppext 01.05.02
Loading...
Searching...
No Matches
semaphore.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3#pragma once
4
5#ifdef __linux__
6# include <features.h>
7#endif
8
9#include <system_error>
10
11#include <cassert>
12
13/*
14 * Two implementations: one is based on the posix semaphore (sem_wait etc.), the
15 * other is pure C++ 11. The posix implementation is considered to be more
16 * efficient, so we use the pure C++ 11 implementation only as a fallback.
17 */
18
19#if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
20/**********************************************************************************************************************
21 * POSIX-based implementation follows
22 *********************************************************************************************************************/
23
24# include <semaphore.h>
25
26namespace cppext {
27
28 class semaphore {
29 public:
31 semaphore() {
32 // create new semaphore which is not shared it between processes
33 int ret = sem_init(&sem, 0, 0);
34 if(ret != 0) throw std::system_error(std::error_code(errno, std::generic_category()));
35 }
36
39 ~semaphore() { sem_destroy(&sem); }
40
45 void unlock() {
46 int ret = sem_post(&sem);
47 if(ret != 0) throw std::system_error(std::error_code(errno, std::generic_category()));
48 // safety check against misuse
49 int value;
50 ret = sem_getvalue(&sem, &value);
51 if(ret != 0 || value > 1) throw std::system_error(std::error_code(errno, std::generic_category()));
52 }
53
56 bool is_ready() {
57 int value;
58 int ret = sem_getvalue(&sem, &value);
59 if(ret != 0) throw std::system_error(std::error_code(errno, std::generic_category()));
60 return value > 0;
61 }
62
68 void wait_and_reset() {
69 int ret = sem_wait(&sem);
70 if(ret != 0) throw std::system_error(std::error_code(errno, std::generic_category()));
71 }
72
75 bool is_ready_and_reset() {
76 int ret = sem_trywait(&sem);
77 if(ret != 0) {
78 if(errno != EAGAIN) throw std::system_error(std::error_code(errno, std::generic_category()));
79 return false;
80 }
81 return true;
82 }
83
84 private:
85 // the POSIX semaphore object
86 sem_t sem;
87 };
88
89} // namespace cppext
90
91#else
92
93/**********************************************************************************************************************
94 * Pure C++ 11 implementation follows
95 *********************************************************************************************************************/
96
97# include <condition_variable>
98
99# include <mutex>
100
101namespace cppext {
102
103 class semaphore {
104 public:
105 semaphore() : _count(1) {}
106
107 void unlock() {
108 std::unique_lock<decltype(_mutex)> lock(_mutex);
109 assert(_count > 0);
110 --_count;
111 if(_count == 0) _condition.notify_one();
112 }
113
114 bool is_ready() {
115 std::unique_lock<decltype(_mutex)> lock(_mutex);
116 return _count == 0;
117 }
118
120 std::unique_lock<decltype(_mutex)> lock(_mutex);
121 while(_count > 0) _condition.wait(lock);
122 _count = 1;
123 }
124
126 std::unique_lock<decltype(_mutex)> lock(_mutex);
127 if(_count == 0) {
128 _count = 1;
129 return true;
130 }
131 return false;
132 }
133
134 private:
135 // mutex required for the condition variable to work
136 std::mutex _mutex;
137
138 // condition variable used for notification
139 std::condition_variable _condition;
140
141 // semaphore counter
142 size_t _count;
143 };
144
145} // namespace cppext
146
147#endif // POSIX feature switch
bool is_ready_and_reset()