ChimeraTK-cppext 01.07.01
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 <cassert>
10#include <system_error>
11
12/*
13 * Two implementations: one is based on the posix semaphore (sem_wait etc.), the
14 * other is pure C++ 11. The posix implementation is considered to be more
15 * efficient, so we use the pure C++ 11 implementation only as a fallback.
16 */
17
18#if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
19/**********************************************************************************************************************
20 * POSIX-based implementation follows
21 *********************************************************************************************************************/
22
23# include <semaphore.h>
24
25namespace cppext {
26
27 class semaphore {
28 public:
30 semaphore() {
31 // create new semaphore which is not shared it between processes
32 int ret = sem_init(&sem, 0, 0);
33 if(ret != 0) throw std::system_error(std::error_code(errno, std::generic_category()));
34 }
35
38 ~semaphore() { sem_destroy(&sem); }
39
44 void unlock() {
45 int ret = sem_post(&sem);
46 if(ret != 0) throw std::system_error(std::error_code(errno, std::generic_category()));
47 // safety check against misuse
48 int value;
49 ret = sem_getvalue(&sem, &value);
50 if(ret != 0 || value > 1) throw std::system_error(std::error_code(errno, std::generic_category()));
51 }
52
55 bool is_ready() {
56 int value;
57 int ret = sem_getvalue(&sem, &value);
58 if(ret != 0) throw std::system_error(std::error_code(errno, std::generic_category()));
59 return value > 0;
60 }
61
67 void wait_and_reset() {
68 int ret = sem_wait(&sem);
69 if(ret != 0) throw std::system_error(std::error_code(errno, std::generic_category()));
70 }
71
74 bool is_ready_and_reset() {
75 int ret = sem_trywait(&sem);
76 if(ret != 0) {
77 if(errno != EAGAIN) throw std::system_error(std::error_code(errno, std::generic_category()));
78 return false;
79 }
80 return true;
81 }
82
83 private:
84 // the POSIX semaphore object
85 sem_t sem;
86 };
87
88} // namespace cppext
89
90#else
91
92/**********************************************************************************************************************
93 * Pure C++ 11 implementation follows
94 *********************************************************************************************************************/
95
96# include <condition_variable>
97# include <mutex>
98
99namespace cppext {
100
101 class semaphore {
102 public:
103 semaphore() : _count(1) {}
104
105 void unlock() {
106 std::unique_lock<decltype(_mutex)> lock(_mutex);
107 assert(_count > 0);
108 --_count;
109 if(_count == 0) _condition.notify_one();
110 }
111
112 bool is_ready() {
113 std::unique_lock<decltype(_mutex)> lock(_mutex);
114 return _count == 0;
115 }
116
118 std::unique_lock<decltype(_mutex)> lock(_mutex);
119 while(_count > 0) _condition.wait(lock);
120 _count = 1;
121 }
122
124 std::unique_lock<decltype(_mutex)> lock(_mutex);
125 if(_count == 0) {
126 _count = 1;
127 return true;
128 }
129 return false;
130 }
131
132 private:
133 // mutex required for the condition variable to work
134 std::mutex _mutex;
135
136 // condition variable used for notification
137 std::condition_variable _condition;
138
139 // semaphore counter
140 size_t _count;
141 };
142
143} // namespace cppext
144
145#endif // POSIX feature switch
bool is_ready_and_reset()