Just::Thread
Pro: Actors EditionThe first release of Just::Thread
Pro is here. The Actors Edition provides a
framework for creating actors that run on separate threads, and communicate via message passing,
as well
as jss::synchronized_value
for synchronizing access to a single object
and jss::concurrent_map
,
a hash map that is safe for concurrent access from multiple threads.
See the overview below for more information, or read the full documentation.
Order your copy of just::thread
Pro: Actors today, and get started within minutes.
Using Actors provides an easy way of structuring your application to use multiple threads without
worrying about the details of mutexes, condition variables and other low-level facilities. Each
jss::actor
runs its task (which can be
a function or callable object) on its own thread, and has an associated message queue.
Actors then send messages to each other either by calling jss::actor::send()
directly on an jss::actor
object, or on an jss::actor_ref
object. Messages can be of any copyable or
movable type, so you can define your messages in whatever way is most appropriate. The
jss::actor::self()
function
provides an easy way to pass around a reference to the current actor. You can use this for passing a
reference to the current actor as part of a message, in order for the receiving actor to send a
response.
Messages are received by
calling jss::actor::receive()
. Calling jss::actor::receive()
on its own will just receive and discard all messages (as no matches are specified) until
a jss::stop_actor
message is
received (in which case
a jss::stop_actor
exception is
thrown). In order to process the messages you need to chain a call to match
on
the jss::actor::receive()
call, specifying the type of message to match, and the function to call to handle it. This could
be a lambda:
jss::actor::receive().match<my_message>([](my_message){ std::cout<<"my message received"<<std::endl; });
This will receive and discard all messages until either a my_message
message is
received, in which case the lambda is run to print "my message received" on standard output, or
a jss::stop_actor
message is
received. Once a message has been
handled, jss::actor::receive()
returns to its caller. If you wish to handle more than one message, just put
the jss::actor::receive()
call
in a loop.
Messages are sent with
the send()
member function:
jss::actor a(actor_func); a.send(my_message());
You can also specify that you wish to process one of several types of message, whichever arrives
first. This can be done by chaining multiple match
calls:
jss::actor::receive() .match<first_message>([](first_message){ std::cout<<"first message type received"<<std::endl; }) .match<second_message>([](second_message){ std::cout<<"second message type received"<<std::endl; });
This
time, jss::actor::receive()
will discard all messages until it receives either a message of type first_message
or
one of type second_message
(or
a jss::stop_actor
message). Again, it returns as soon as one message has been processed, whichever type it is. Any
number of match
calls can be chained in this way, and
the jss::actor::receive()
call
will block until one of the specified messages has been received.
The jss::mpsc_fifo
class
template provides an unbounded FIFO queue. Multiple threads may safely add items to the queue
concurrently, provided only a single thread is removing items from the queue. This is used to
provide the underlying message queue for the actors.
The jss::concurrent_map
class template provides a hash-based map which is safe for concurrent access from multiple
threads, including adding and removing elements concurrently with lookups and iteration. The
interface is modelled on std::unordered_map
, with an
added insert_or_replace
member function for replacing a stored element with another.
The jss::synchronized_value
class template provides synchronization for all accesses to a single object.
It is a simple wrapper around an object of the specified type, and the interface is modelled on a smart pointer, with accesses done using the pointer dereference and indirection operators.
jss::synchronized_value<std::string> s; void foo(){ if(s->empty()){ *s = "hello"; } }
In this example, multiple calls to foo
can happen concurrently on separate threads,
and all accesses to s
are protected.
Order your copy of just::thread
Pro: Actors today, and get started within minutes.