iLab Neuromorphic Robotics Toolkit  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
nrt::MessagePosterResults< Posting > Class Template Reference

#include <nrt/Core/Blackboard/MessagePosterResults.H>

template<class Posting>
class nrt::MessagePosterResults< Posting >

The results of a post()

This essentially is a list of std::future objects, one for each callback that was triggered by a post(). Each future provides access to the future result of one callback triggered (in a parallel thread) by the post(), and that result becomes ready and available when the thread executing the callback completes. Additional convenience interface is provided to wait for all callbacks to have completed their work, to check whether some result is available and ready, and to get() the next result. Note that some of the futures may throw when you attempt a get() on them, if the associated callback threw. We do not implement perfect exception forwarding; instead, the only exceptions that one might expect here are either nrt::exception::BlackboardException (when something went wrong at the Blackboard level, e.g., a network error communicating with a remote Blackboard), or nrt::exception::ModuleException (when something went wrong in the callback function and it threw). Any other exceptions that callbacks may throw are wrapped into an nrt::exception::ModuleException.

Canonical use is:

// Declare some poster port for our class called 'MyPoster' which will post a MyMessage, and will expect some
// MyReturnMessage in return.
NRT_DECLARE_MESSAGEPOSTER_PORT(MyPoster, MyMessage, MyReturnMessage, "Post/Receive Request");
//...
// Post and block until all callbacks are done, trash any results, propagate any callback exception
std::unique_ptr<MyMessage> message(new MyMessage());
MyPoster::post(message));

If you care about the results, then:

// Post and process the results as soon as they are available, otherwise sleep until the next result appears
std::unique_ptr<MyMessage> message(new MyMessage());
if (MyPoster::PostResultsType result = MyPoster::post(message))
{
// Ok, at least one callback, and possibly several, were triggered by our post. Let's get the results:
while (! result.empty() ) {
std::shared_ptr<MyReturnMessage const> retmsg = result.get();
// do something with retmsg
}
}

If you want to handle exceptions, typical usage becomes:

std::unique_ptr<MyMessage> message(new MyMessage());
if (auto result = MyMessage::post(message))
while (! result.empty() )
try
{
NRT_INFO(" Received result from post(): " << result.get());
}
{ NRT_WARNING(" Received Blackboard exception from post():\n" << e.str()); throw; }
{ NRT_WARNING(" Received Module exception from post():\n" << e.str()); throw; }
catch (...)
{ NRT_WARNING(" Received unknown exception from post()! Re-throwing it."); throw; }

Note that once you catch an exception, you should either handle the error and swallow the exception, or, if you are not going to handle it, just re-throw it as is. The Blackboard will then automatically update the exception as it propagates it up the caller chain, so that a full trace of nested calls will be visible from the exception.

Finally, if you have other things to do while callbacks triggered by your post are processed, and you do not want to block, then just do something like:

std::unique_ptr<MyMessage> message(new MyMessage());
if (auto result = MyMessage::post(message))
while (! result.empty() )
if (result.ready()) {
// Get the next result, this will not block but may throw
std::shared_ptr<MyMessage const> msg = result.get();
// Do something with msg
} else {
// Do something else, sleep, etc for some time, while we wait for the next result to be ready.
}

Note that MessagePosterResults is not inherently thread-safe, so in the unlikely event that you may have several threads consuming its results, you would have to ensure thread safety with an external mutex.

Alternatively to the above way of using results, you can also use an iterator-based syntax explained with the iterator definition below. See test-ResultsSyntax.C for examples.

Definition at line 150 of file MessagePosterResults.H.

Public Member Functions

 MessagePosterResults ()
 Default Constructor, contains no data.
 
 MessagePosterResults (MessagePosterResults< Posting > &&other)
 Constructor with move semantics.
 
 MessagePosterResults (MessagePosterResults< Posting > &other)=delete
 Forbid copy construction.
 
MessagePosterResults< Posting > & operator= (MessagePosterResults< Posting > &&other)
 Move Assignment operator.
 
MessagePosterResults< Posting > & operator= (MessagePosterResults< Posting > const &other)=delete
 Forbid copy-assignment.
 
 ~MessagePosterResults ()
 Destructor. Will block and wait on any result that is still pending and then get() it, which may throw. More...
 
bool waitall (std::chrono::microseconds const maxwait=std::chrono::hours::max())
 Wait for all callbacks to complete, up to a maximum total wait time. More...
 
bool ready ()
 Is there one or more messages ready now, such that one call to get() would return it without any blocking?
 
size_t size ()
 Number of futures left, ready or not.
 
bool empty ()
 Are we empty? This is faster than testing size() == 0 (see why in the doc of std::list)
 
 operator bool ()
 Returns true if we are not empty.
 
Posting::RetPtr get ()
 Get the next available result. More...
 
void waitgetall ()
 Wait for all results and run a get() on each of them, then trash the obtained return values. More...
 
iterator begin ()
 Get access to the first iterator. More...
 
iterator end ()
 Create an iterator that is equivalent to the 'end' of the sequence of futures. More...
 

Friends

class nrt::MessagePosterCore< Posting >
 
class iterator
 

Constructor & Destructor Documentation

template<class Posting >
nrt::MessagePosterResults< Posting >::~MessagePosterResults ( )
inline

Destructor. Will block and wait on any result that is still pending and then get() it, which may throw.

Yes this is a potentially throwing destructor, but that's ok as long as people don't derive from MessagePosterResults (destructor is not virtual anyway). If you want to avoid waiting and possibly throwing here, just make sure that you waitall() and get() everything before your results run out of scope.

Definition at line 72 of file MessagePosterResultsImpl.H.

Member Function Documentation

template<class Posting >
bool nrt::MessagePosterResults< Posting >::waitall ( std::chrono::microseconds const  maxwait = std::chrono::hours::max())
inline

Wait for all callbacks to complete, up to a maximum total wait time.

Returns true if all callbacks have completed within the max allotted wait time. With the default value of maxwait, we block until all callbacks have indeed completed, and always return true. If you just want to check for completion without blocking, just pass a zero maxwait duration. Note that waitall() just waits and does not examine the results, hence it will not throw any exception possibly thrown by one of the callbacks. Exceptions, if any, are thrown by get() or waitgetall().

Definition at line 81 of file MessagePosterResultsImpl.H.

References nrt::now().

template<class Posting >
Posting::RetPtr nrt::MessagePosterResults< Posting >::get ( )
inline

Get the next available result.

We return results as soon as they become ready, so they come in unspecified order. Calling get() will possibly block until the next result is available, test for ready() before you call get() if you want to be sure to not block. Calling get() will possibly throw an exception if the associated callback threw.

Definition at line 129 of file MessagePosterResultsImpl.H.

template<class Posting >
void nrt::MessagePosterResults< Posting >::waitgetall ( )
inline

Wait for all results and run a get() on each of them, then trash the obtained return values.

This is useful if the return type of the posting is void or if you don't care about return values, but want to make sure that everything completed correctly without throwing any exception. Just waiting using waitall() will not reveal any exceptions that were thrown by callbacks. Note that the MessagePosterResults destructor calls waitgetall, so it may block and throw if you have not taken care of all results already.

Definition at line 152 of file MessagePosterResultsImpl.H.

template<class Posting >
nrt::MessagePosterResults< Posting >::iterator nrt::MessagePosterResults< Posting >::begin ( )

Get access to the first iterator.

Warning
You may only call begin() once on a MessagePosterResult. Trying to call begin() multiple times will cause a std::range_error exception to be thrown.

Definition at line 208 of file MessagePosterResultsImpl.H.

template<class Posting >
nrt::MessagePosterResults< Posting >::iterator nrt::MessagePosterResults< Posting >::end ( )

Create an iterator that is equivalent to the 'end' of the sequence of futures.

An iterator created by end() is the only

Definition at line 217 of file MessagePosterResultsImpl.H.


The documentation for this class was generated from the following files: