21#ifndef MTCORE_THREAD_CHANNELS_HPP
22#define MTCORE_THREAD_CHANNELS_HPP
29#include <condition_variable>
69 "MISMATCHED CLOSED ERROR");
72 "MISMATCHED CLOSED ERROR");
116 template<
typename T,
size_t Size = 1>
118 static_assert(Size > 0,
"CANNOT HAVE UNBUFFERED THREAD-BASED CHANNELS");
121 std::timed_mutex channelMux = {};
122 std::condition_variable_any read_cond = {};
123 std::condition_variable_any send_cond = {};
134 auto lock = std::unique_lock(channelMux);
136 read_cond.notify_all();
137 send_cond.notify_all();
149 auto lock = std::unique_lock(channelMux, std::try_to_lock_t{});
151 if (!lock.owns_lock()) {
159 ensure(lock.owns_lock(),
"DID NOT LOCK!");
160 if (sendImpl(msg).is_error()) {
173 auto lock = std::unique_lock(channelMux);
174 while (!closed && q.is_full()) {
175 send_cond.wait(lock);
178 ensure(lock.owns_lock(),
"DID NOT LOCK!");
179 return sendImpl(msg);
191 template<
typename Clock = std::chrono::steady_clock>
193 const std::chrono::time_point<Clock> &when) {
194 auto lock = std::unique_lock(channelMux, when);
196 if (!lock.owns_lock()) {
200 while (!closed && q.is_full()) {
201 if (send_cond.wait_until(lock, when) == std::cv_status::timeout) {
206 ensure(lock.owns_lock(),
"DID NOT LOCK!");
207 if (sendImpl(msg).is_error()) {
222 auto lock = std::unique_lock(channelMux, std::try_to_lock_t{});
224 if (!lock.owns_lock()) {
235 ensure(lock.owns_lock(),
"DID NOT LOCK!");
245 auto lock = std::unique_lock(channelMux);
247 while (!closed && q.is_empty()) {
248 read_cond.wait(lock);
251 ensure(lock.owns_lock(),
"DID NOT LOCK");
263 template<
typename Clock>
266 auto lock = std::unique_lock(channelMux, when);
268 if (!lock.owns_lock()) {
272 while (!closed && q.is_empty()) {
273 if (read_cond.wait_until(lock, when) == std::cv_status::timeout) {
278 ensure(lock.owns_lock(),
"DID NOT LOCK");
290 read_cond.notify_one();
294 Optional<T> readImpl() {
298 ensure(!q.is_empty(),
"CANNOT READ FROM EMPTY BUFFER");
299 send_cond.notify_one();
constexpr auto nullopt
Placeholder value for an empty Optional.
ChannelReceiveBeforeErrors
Errors for when timed receives fail Note: If the channel is closed, a nullopt will be returned instea...
ChannelTrySendErrors
Errors for when non-blocking sends fail.
ChannelSendBlockErrors
Errors for when blocking sends fail.
ChannelSendBeforeErrors
Errors for when timed blocking sends fail.
ChannelTryReceiveErrors
Errors for when non-blocking receives fail Note: If the channel is closed, a nullopt will be returned...
#define ensure(check,...)
Ensures that a check holds true, aborts the program if not true Will print error if the condition is ...
Success< void > success()
Creates a successful void Result object.
Error< Underlying > error(Underlying err)
Creates an error.
constexpr bool is_channel_like
Checks if a type is channel-like.
constexpr bool has_closed_error
Checks if an error type has a recognized closed error.
Thread-related namespace The methods and classes provided by this class are thread-safe Classes and m...
Statically allocated FIFO queue with fixed maximum capacity.
Result< void, CollectionAddNoAllocationError > push(const T &elem) noexcept
Tries to add an element to the Queue Fails if Queue is empty.
bool is_full() const noexcept
Checks if ring buffer is full.
bool is_empty() const noexcept
Checks if ring buffer is empty.
Represents a value that may or may not exist (an "Optional" value) Similar concept to std::optional,...
Represents a Result that may have an error (error code) or a success value A type of "void" means the...
Channel is a message-passing primitive between two threads A channel has blocking and non-blocking (o...
Result< void, ChannelSendBlockErrors > send_block(const T &msg)
Will send a message (unless the channel is closed, then will fail) Will block as long as is needed to...
Optional< Message > receive_block()
Receives a message from the channel Blocks indefinitely.
Result< void, ChannelTrySendErrors > try_send(const T &msg)
Tries to send a message Does not block If there is no room or would have to block for locking,...
Result< Optional< T >, ChannelReceiveBeforeErrors > receive_before(const std::chrono::time_point< Clock > &when)
Receives a message before a time point Blocks until a time point.
Result< Optional< T >, ChannelTryReceiveErrors > try_receive()
Tries to receive a message Will fail if it would have to block If the channel is empty and closed,...
Result< void, ChannelSendBeforeErrors > send_before(const T &msg, const std::chrono::time_point< Clock > &when)
Will send a message (unless the channel is closed, will fail) Will block up to a certain time point,...
void close()
Closes the channel.