MT Core (C++)
Core library for replacing C++ standard in project usage
Loading...
Searching...
No Matches
mtcore::thread::Inbox< T > Struct Template Reference

Inter-thread communication primitive to send messages between threads Has a growable Queue. More...

#include <inbox.hpp>

Public Types

using Message = T
 

Public Member Functions

Result< void, AllocationErrorinit (Allocator &alloc, size_t initCapacity=10)
 Initializes a new message Queue.
 
void deinit (Allocator &alloc)
 Cleans up memory Note: All references to the inbox MUST be cleaned up BEFORE calling this method.
 
void close ()
 Closes an inbox.
 
Result< void, ChannelTrySendErrorstry_send (const T &msg)
 Send message without blocking Will NOT grow inbox Queue and will instead fail.
 
Result< void, ChannelSendBlockErrorssend_block (const T &msg)
 Send message, will block indefinitely Will NOT grow inbox Queue and will instead block.
 
template<typename Clock = std::chrono::steady_clock, typename Duration>
Result< void, ChannelSendBeforeErrorssend_before (const T &msg, const std::chrono::time_point< Clock, Duration > &when)
 Send message before a timeout Will NOT grow inbox Queue and will instead block.
 
Result< void, ChannelGrowTrySendErrorstry_send (Allocator &alloc, const T &msg)
 Send message without blocking Will grow inbox Queue if needed If unable to grow, will return an error.
 
Result< void, ChannelGrowSendBlockErrorssend_block (Allocator &alloc, const T &msg)
 Send message and block indefinitely Will grow inbox Queue if needed If unable to grow, will instead block.
 
template<typename Clock = std::chrono::steady_clock, typename Duration>
Result< void, ChannelGrowSendBeforeErrorssend_before (Allocator &alloc, const T &msg, const std::chrono::time_point< Clock, Duration > &when)
 Send message before a timeout Will grow inbox Queue if needed If unable to grow, will instead block.
 
Result< Optional< T >, ChannelTryReceiveErrorstry_receive ()
 Tries to receive a message Will fail if it would have to block If the channel is empty and closed, will return nullopt instead of a message.
 
Optional< T > receive_block ()
 Receives a message from the channel Blocks indefinitely.
 
template<typename Clock, typename Duration>
Result< Optional< T >, ChannelSendBeforeErrorsreceive_before (const std::chrono::time_point< Clock, Duration > &when)
 Receives a message before a time point Blocks until a time point.
 
bool is_initialized () const noexcept
 Checks if the inbox is initialized inboxes which aren't initialized will abort if used.
 
void shrinkToFit (Allocator &alloc)
 Shrinks Queue to fit current Queue size Useful to lower memory usage.
 

Detailed Description

template<typename T>
struct mtcore::thread::Inbox< T >

Inter-thread communication primitive to send messages between threads Has a growable Queue.

Locks:

  • 1 for entire data structure

Condition Variables:

  • 2 condition variables (one to send, one to receive)

Non-Blocking Availability:

  • With Failure
Template Parameters
TType of messages to send

Definition at line 75 of file inbox.hpp.

Member Typedef Documentation

◆ Message

template<typename T>
using mtcore::thread::Inbox< T >::Message = T

Definition at line 84 of file inbox.hpp.

Member Function Documentation

◆ close()

template<typename T>
void mtcore::thread::Inbox< T >::close ( )
inline

Closes an inbox.

Does NOT clean up memory Memory cleanup must be handled by deinit

Definition at line 114 of file inbox.hpp.

114 {
115 auto lock = std::unique_lock(channelMux);
116 ensure(initialized(), "NOT INITIALIZED!");
117 closed = true;
118 send_cond.notify_all();
119 read_cond.notify_all();
120 }
#define ensure(check,...)
Ensures that a check holds true, aborts the program if not true Will print error if the condition is ...
Inter-thread communication primitive to send messages between threads Has a growable Queue.
Definition inbox.hpp:75

◆ deinit()

template<typename T>
void mtcore::thread::Inbox< T >::deinit ( Allocator & alloc)
inline

Cleans up memory Note: All references to the inbox MUST be cleaned up BEFORE calling this method.

Parameters
allocAllocator to use to clean up memory

Definition at line 104 of file inbox.hpp.

104 {
105 auto lock = std::unique_lock(channelMux);
106 q.deinit(alloc);
107 ensure(!initialized(), "CLEAN UP FAILED!");
108 }

◆ init()

template<typename T>
Result< void, AllocationError > mtcore::thread::Inbox< T >::init ( Allocator & alloc,
size_t initCapacity = 10 )
inline

Initializes a new message Queue.

Parameters
allocAllocator to initialize Queue with
initCapacityInitial capacity (can optionally grow)
Returns
success or failure

Definition at line 92 of file inbox.hpp.

92 {
93 auto lock = std::unique_lock(channelMux);
94 ensure(!initialized(), "Already initialized! memory leak detected!");
95 return q.init(alloc, initCapacity);
96 }

◆ is_initialized()

template<typename T>
bool mtcore::thread::Inbox< T >::is_initialized ( ) const
inlinenodiscardnoexcept

Checks if the inbox is initialized inboxes which aren't initialized will abort if used.

Returns
true if initialized, false otherwise

Definition at line 417 of file inbox.hpp.

417 {
418 auto lock = std::unique_lock(channelMux);
419 return initialized();
420 }

◆ receive_before()

template<typename T>
template<typename Clock, typename Duration>
Result< Optional< T >, ChannelSendBeforeErrors > mtcore::thread::Inbox< T >::receive_before ( const std::chrono::time_point< Clock, Duration > & when)
inlinenodiscard

Receives a message before a time point Blocks until a time point.

If does not receive before then, will fail

Template Parameters
ClockClock type for the time point
Parameters
whenWhen should it timeout
Returns
Message received or nullopt if channel is closed, or error if timed out

Definition at line 394 of file inbox.hpp.

394 {
395 auto lock = std::unique_lock(channelMux, when);
396
397 if (!lock.owns_lock()) {
399 }
400 ensure(initialized(), "NOT INITIALIZED!");
401
402 while (!closed && q.is_empty()) {
403 if (read_cond.wait_until(lock, when) == std::cv_status::timeout) {
405 }
406 }
407
408 ensure(lock.owns_lock(), "DID NOT LOCK");
409 return readImpl();
410 }
Error< Underlying > error(Underlying err)
Creates an error.
Definition result.hpp:425
Here is the call graph for this function:

◆ receive_block()

template<typename T>
Optional< T > mtcore::thread::Inbox< T >::receive_block ( )
inlinenodiscard

Receives a message from the channel Blocks indefinitely.

Returns
Returns message received, or nullopt if channel is closed

Definition at line 372 of file inbox.hpp.

372 {
373 auto lock = std::unique_lock(channelMux);
374 ensure(initialized(), "NOT INITIALIZED!");
375
376 while (!closed && q.is_empty()) {
377 read_cond.wait(lock);
378 }
379
380 ensure(lock.owns_lock(), "DID NOT LOCK");
381 return readImpl();
382 }

◆ send_before() [1/2]

template<typename T>
template<typename Clock = std::chrono::steady_clock, typename Duration>
Result< void, ChannelGrowSendBeforeErrors > mtcore::thread::Inbox< T >::send_before ( Allocator & alloc,
const T & msg,
const std::chrono::time_point< Clock, Duration > & when )
inlinenodiscard

Send message before a timeout Will grow inbox Queue if needed If unable to grow, will instead block.

Template Parameters
ClockClock for measuring time
Parameters
allocAllocator for growing Queue
msgMessage to send
whenTime point to send before
Returns
success or failure

Definition at line 297 of file inbox.hpp.

297 {
298 auto lock = std::unique_lock(channelMux, when);
299 if (!lock.owns_lock()) {
301 }
302 ensure(initialized(), "NOT INITIALIZED!");
303
304 if (is_closed()) {
306 }
307
308 bool emit_notice = q.is_full();
309
310 auto res = q.push(alloc, msg);
311 if (res.is_error()) {
313 // If we couldn't resize, just wait for room
314 emit_notice = false;
315 while (!is_closed() && q.is_full()) {
316 if (send_cond.wait_until(lock, when) == std::cv_status::timeout) {
318 }
319 }
320
321 // check if we closed
322 if (is_closed()) {
324 }
325
326 // try sending again
327 if (auto err = q.push(msg); err.is_error()) {
329 }
330 }
331 read_cond.notify_one();
332
333 // tell everyone else our capacity has grown
334 if (emit_notice) {
335 send_cond.notify_all();
336 }
337 return success();
338 }
Success< void > success()
Creates a successful void Result object.
Definition result.hpp:398
Here is the call graph for this function:

◆ send_before() [2/2]

template<typename T>
template<typename Clock = std::chrono::steady_clock, typename Duration>
Result< void, ChannelSendBeforeErrors > mtcore::thread::Inbox< T >::send_before ( const T & msg,
const std::chrono::time_point< Clock, Duration > & when )
inlinenodiscard

Send message before a timeout Will NOT grow inbox Queue and will instead block.

Template Parameters
ClockClock for measuring time
Parameters
msgMessage to send
whenTime point to send before
Returns
success or failure

Definition at line 182 of file inbox.hpp.

182 {
183 auto lock = std::unique_lock(channelMux, when);
184 if (!lock.owns_lock()) {
186 }
187 ensure(initialized(), "NOT INITIALIZED!");
188
189 while (!closed && q.is_full()) {
190 if (send_cond.wait_until(lock, when) == std::cv_status::timeout) {
192 }
193 }
194 if (closed) {
196 }
197
198 (void) q.push(msg);
199 read_cond.notify_one();
200 return success();
201 }
Here is the call graph for this function:

◆ send_block() [1/2]

template<typename T>
Result< void, ChannelGrowSendBlockErrors > mtcore::thread::Inbox< T >::send_block ( Allocator & alloc,
const T & msg )
inlinenodiscard

Send message and block indefinitely Will grow inbox Queue if needed If unable to grow, will instead block.

Parameters
allocAllocator for growing Queue
msgMessage to send
Returns
success or failure

Definition at line 245 of file inbox.hpp.

245 {
246 auto lock = std::unique_lock(channelMux);
247 ensure(lock.owns_lock(), "DID NOT LOCK");
248 ensure(initialized(), "NOT INITIALIZED!");
249
250 while (!closed && q.is_full()) {
251 send_cond.wait(lock);
252 }
253 if (closed) {
255 }
256
257 bool emit_notice = q.is_full();
258 auto res = q.push(alloc, msg);
259 if (res.is_error()) {
260 // If we couldn't resize, just wait for room
261 emit_notice = false;
262 while (!is_closed() && q.is_full()) {
263 send_cond.wait(lock);
264 }
265
266 // check if we closed
267 if (is_closed()) {
269 }
270
271 // try sending again
272 if (auto err = q.push(msg); err.is_error()) {
274 }
275 }
276 read_cond.notify_one();
277
278 // tell everyone else our capacity has grown
279 if (emit_notice) {
280 send_cond.notify_all();
281 }
282 return success();
283 }
Here is the call graph for this function:

◆ send_block() [2/2]

template<typename T>
Result< void, ChannelSendBlockErrors > mtcore::thread::Inbox< T >::send_block ( const T & msg)
inlinenodiscard

Send message, will block indefinitely Will NOT grow inbox Queue and will instead block.

Parameters
msgMessage to send
Returns
success or failure

Definition at line 155 of file inbox.hpp.

155 {
156 auto lock = std::unique_lock(channelMux);
157 ensure(lock.owns_lock(), "DID NOT LOCK");
158 ensure(initialized(), "NOT INITIALIZED!");
159
160 while (!closed && q.is_full()) {
161 send_cond.wait(lock);
162 }
163 if (closed) {
165 }
166
167 (void) q.push(msg);
168 read_cond.notify_one();
169 return success();
170 }
Here is the call graph for this function:

◆ shrinkToFit()

template<typename T>
void mtcore::thread::Inbox< T >::shrinkToFit ( Allocator & alloc)
inline

Shrinks Queue to fit current Queue size Useful to lower memory usage.

Parameters
allocAllocator to use to free memory

Definition at line 427 of file inbox.hpp.

427 {
428 auto lock = std::unique_lock(channelMux);
429 ensure(lock.owns_lock(), "DID NOT LOCK");
430 ensure(initialized(), "NOT INITIALIZED!");
431
432 q.shrink_to_fit(alloc);
433 }

◆ try_receive()

template<typename T>
Result< Optional< T >, ChannelTryReceiveErrors > mtcore::thread::Inbox< T >::try_receive ( )
inlinenodiscard

Tries to receive a message Will fail if it would have to block If the channel is empty and closed, will return nullopt instead of a message.

Returns
Message, nullopt, or failure. Message if available, nullopt if closed, failure if would have to block

Definition at line 348 of file inbox.hpp.

348 {
349 auto lock = std::unique_lock(channelMux, std::try_to_lock_t{});
350
351 if (!lock.owns_lock()) {
353 }
354 ensure(initialized(), "NOT INITIALIZED!");
355
356 if (q.is_empty()) {
357 if (closed) {
358 return readImpl();
359 }
361 }
362
363 ensure(lock.owns_lock(), "DID NOT LOCK!");
364 return readImpl();
365 }
Here is the call graph for this function:

◆ try_send() [1/2]

template<typename T>
Result< void, ChannelGrowTrySendErrors > mtcore::thread::Inbox< T >::try_send ( Allocator & alloc,
const T & msg )
inlinenodiscard

Send message without blocking Will grow inbox Queue if needed If unable to grow, will return an error.

Parameters
allocAllocator for growing Queue
msgMessage to send
Returns
success or failure

Definition at line 211 of file inbox.hpp.

211 {
212 auto lock = std::unique_lock(channelMux, std::try_to_lock_t{});
213
214 if (!lock.owns_lock()) {
216 }
217 ensure(initialized(), "NOT INITIALIZED!");
218
219 if (closed) {
221 }
222
223 bool emit_notice = q.is_full();
224 auto res = q.push(alloc, msg);
225 if (res.is_error()) {
227 }
228 read_cond.notify_one();
229
230 // tell everyone else our capacity has grown
231 if (emit_notice) {
232 send_cond.notify_all();
233 }
234 return success();
235 }
Here is the call graph for this function:

◆ try_send() [2/2]

template<typename T>
Result< void, ChannelTrySendErrors > mtcore::thread::Inbox< T >::try_send ( const T & msg)
inlinenodiscard

Send message without blocking Will NOT grow inbox Queue and will instead fail.

Parameters
msgMessage to send
Returns
success or failure

Definition at line 128 of file inbox.hpp.

128 {
129 auto lock = std::unique_lock(channelMux, std::try_to_lock_t{});
130 ensure(initialized(), "NOT INITIALIZED!");
131
132 if (!lock.owns_lock()) {
134 }
135
136 if (closed) {
138 }
139
140 if (q.is_full()) {
142 }
143
144 (void) q.push(msg);
145 read_cond.notify_one();
146 return success();
147 }
Here is the call graph for this function:

The documentation for this struct was generated from the following file: