![]() | ![]() | ![]() | The actor traits Reactor, ReplyReactor, and Actor | Contents | Index |
Reactor is the super trait of all actor traits. Extending this
trait allows defining actors with basic capabilities to send and
receive messages.
The behavior of a Reactor is defined by implementing its
act method. The act method is executed once the
Reactor is started by invoking start, which also returns
the Reactor. The start method is idempotent which
means that invoking it on an actor that has already been started has
no effect.
The Reactor trait has a type parameter Msg which
indicates the type of messages that the actor can receive.
Invoking the Reactor's ! method sends a message to the
receiver. Sending a message using ! is asynchronous which means
that the sending actor does not wait until the message is received;
its execution continues immediately. For example, a ! msg sends
msg to a. All actors have a mailbox which buffers
incoming messages until they are processed.
The Reactor trait also defines a forward method. This
method is inherited from OutputChannel. It has the same effect
as the ! method. Subtraits of Reactor, in particular the
ReplyReactor trait, override this method to enable implicit
reply destinations (see below).
A Reactor receives messages using the react
method.1 react expects an
argument of type PartialFunction[Msg, Unit] which defines how
messages of type Msg are handled once they arrive in the
actor's mailbox. In the following example, the current actor waits to
receive the string ""Hello", and then prints a greeting:
react {
case "Hello" => println("Hi there")
}
Invoking react never returns. Therefore, any code that should
run after a message has been received must be contained inside the
partial function that is passed to react. For example, two
messages can be received in sequence by nesting two invocations of
react:
react {
case Get(from) =>
react {
case Put(x) => from ! x
}
}
The Reactor trait also provides control structures (see
*) which simplify programming with
react.
The execution of a Reactor terminates when the body of its
act method has run to completion. A Reactor can also
terminate itself explicitly using the exit method. The return
type of exit is Nothing, because exit always
throws an exception. This exception is only used internally, and
should never be caught.
A terminated Reactor can be restarted by invoking its
restart method. Invoking restart on a Reactor
that has not terminated, yet, throws an
IllegalStateException. Restarting a terminated actor causes its
act method to be rerun.
Reactor defines a method getState which returns the
actor's current execution state as a member of the Actor.State
enumeration. An actor that has not been started, yet, is in state
Actor.State.New. An actor that can run without waiting for a
message is in state Actor.State.Runnable. An actor that is
suspended, waiting for a message is in state
Actor.State.Suspended. A terminated actor is in state
Actor.State.Terminated.
The exceptionHandler member allows defining an exception
handler that is enabled throughout the entire lifetime of a
Reactor:
def exceptionHandler: PartialFunction[Exception, Unit]
exceptionHandler returns a partial function which is used to
handle exceptions that are not otherwise handled: whenever an
exception propagates out of the body of a Reactor's act
method, the partial function is applied to that exception, allowing
the actor to run clean-up code before it terminates. Note that the
visibility of exceptionHandler is protected.
Handling exceptions using exceptionHandler works well together
with the control structures for programming with react (see
*). Whenever an exception has been handled
using the partial function returned by exceptionHandler,
execution continues with the current continuation closure. Example:
loop {
react {
case Msg(data) =>
if (cond) // process data
else throw new Exception("cannot process data")
}
}
Assuming that the Reactor overrides exceptionHandler,
after an exception thrown inside the body of react is handled,
execution continues with the next loop iteration.
The ReplyReactor trait extends Reactor[Any] and adds or
overrides the following methods:
! method is overridden to obtain a reference to the
current actor (the sender); together with the actual message, the
sender reference is transferred to the mailbox of the receiving
actor. The receiver has access to the sender of a message through
its sender method (see below).
forward method is overridden to obtain a reference to
the sender of the message that is currently being
processed. Together with the actual message, this reference is
transferred as the sender of the current message. As a consequence,
forward allows forwarding messages on behalf of actors
different from the current actor.
sender method returns the sender of the message
that is currently being processed. Given the fact that a message
might have been forwarded, sender may not return the actor
that actually sent the message.
reply method sends a message back to the sender
of the last message. reply is also used to reply to a
synchronous message send or a message send with future (see below).
!? methods provide synchronous message
sends. Invoking !? causes the sending actor to wait until
a response is received which is then returned. There are two
overloaded variants. The two-parameter variant takes in addition a
timeout argument (in milliseconds), and its return type is
Option[Any] instead of Any. If the sender does not
receive a response within the specified timeout period, !?
returns None, otherwise it returns the response wrapped in
Some.
!! methods are similar to synchronous message
sends in that they allow transferring a response from the
receiver. However, instead of blocking the sending actor until a
response is received, they return Future instances. A
Future can
be used to retrieve the response of the receiver once it is
available; it can also be used to find out whether the response is
already available without blocking the sender (). There are two
overloaded variants. The two-parameter variant takes in addition an
argument of type PartialFunction[Any, A]. This partial
function is used for post-processing the receiver's
response. Essentially, !! returns a future which applies the
partial function to the response once it is received. The result of
the future is the result of this post-processing.
reactWithin method allows receiving messages
within a given period of time. Compared to react it takes an
additional parameter msec which indicates the time period in
milliseconds until the special TIMEOUT pattern matches
(TIMEOUT is a case object in package
scala.actors). Example:
reactWithin(2000) {
case Answer(text) => // process text
case TIMEOUT => println("no answer within 2 seconds")
}
The reactWithin method also allows non-blocking access to the
mailbox. When specifying a time period of 0 milliseconds, the mailbox
is first scanned to find a matching message. If there is no matching
message after the first scan, the TIMEOUT pattern matches. For
example, this enables receiving certain messages with a higher
priority than others:
reactWithin(0) {
case HighPriorityMsg => // ...
case TIMEOUT =>
react {
case LowPriorityMsg => // ...
}
}
In the above example, the actor first processes the next
HighPriorityMsg, even if there is a LowPriorityMsg that
arrived earlier in its mailbox. The actor only processes a
LowPriorityMsg first if there is no
HighPriorityMsg in its mailbox.
In addition, ReplyReactor adds the
Actor.State.TimedSuspended execution state. A suspended actor,
waiting to receive a message using reactWithin is in state
Actor.State.TimedSuspended.
The Actor trait extends ReplyReactor and adds or
overrides the following members:
receive method behaves like react except
that it may return a result. This is reflected in its type, which is
polymorphic in its result:
def receive[R](f: PartialFunction[Any, R]): R
However, using receive makes the actor more heavyweight,
since receive blocks the underlying thread while the actor is
suspended waiting for a message. The blocked thread is unavailable
to execute other actors until the invocation of receive
returns.
link and unlink methods allow an actor
to link and unlink itself to and from another actor,
respectively. Linking can be used for monitoring and reacting to the
termination of another actor. In particular, linking affects the
behavior of invoking exit as explained in the API
documentation of the
Actor
trait.
trapExit member allows reacting to the termination of
linked actors independently of the exit reason (that is, it does not
matter whether the exit reason is 'normal or not). If an
actor's trapExit member is set to true, this actor
will never terminate because of linked actors. Instead, whenever one
of its linked actors terminates it will receive a message of type
Exit. The Exit case class has two members: from
refers to the actor that terminated; reason refers to the
exit reason.
When terminating the execution of an actor, the exit reason can be set
explicitly by invoking the following variant of exit:
def exit(reason: AnyRef): Nothing
An actor that terminates with an exit reason different from the symbol
'normal propagates its exit reason to all actors linked to
it. If an actor terminates because of an uncaught exception, its exit
reason is an instance of the
UncaughtException
case class.
The Actor trait adds two new execution states. An actor
waiting to receive a message using receive is in state
Actor.State.Blocked. An actor waiting to receive a message
using receiveWithin is in state
Actor.State.TimedBlocked.
![]() | ![]() | ![]() | The actor traits Reactor, ReplyReactor, and Actor | Contents | Index |