timedPong.cpp

This example extends the pong example and shows how to receive messages with a timeout, demonstrates registerName/whereisName and how to use lambda functors with Invoker.

#include "acedia/actor.hpp"
#include "acedia/acedia.hpp"

#include <iostream>

#include <boost/cstdint.hpp>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>

typedef boost::int32_t i32;

ACEDIA_DECLARE_CASE_TUPLE1((GameBall), hits, boost::int32_t);

// This implementation of Ping exits if no message was received within
// 100 milliseconds and does not need to get killed by an abnormal exit
// of a link or by a special message.
class Ping : public acedia::Actor
{
    
    // See the pong example
    void returnPass(i32 hits)
    {
        std::cout << "Ping: "
                  << lastReceivedMessage().toString().const_str()
                  << std::endl;
        reply(GameBall(hits+1));
    }
    
 protected:
    
    virtual void act()
    {
        using acedia::on;
        
        // If you define an invoker with one rule you can pass
        // this rule to its constructor instead of call "add".
        acedia::Invoker i(on<GameBall>().unbox() >> method(&Ping::returnPass));
        
        // Receive message until receiveAndInvokeWithin() returns false.
        while (receiveAndInvokeWithin(i, 100)) { }
        
        // We reach this point only if a timeout occurs.
        std::cout << "Ping: timeout (quit)" << std::endl;
    }
    
};

// This implementation of Pong overrides only the act() member function
// and does not need any data fields or additional member functions.
// It uses a lambda functor as callback for acedia::Invoker
// and whereisName() to find ping instead of a constructor argument.
class Pong : public acedia::Actor
{
 protected:
    
    virtual void act()
    {
        // Local variables and using delcarations.
        using acedia::on;
        using boost::lambda::var;
        using boost::lambda::_1;
        i32 hits = -1; // start with -1 because we always add 1
        
        // Get the spawned Ping instance by name.
        // Note: Names are case sensitive!
        acedia::ActorRef ping = acedia::whereisName("ping");
        
        // Set the local variable hits to the received value with a
        // lambda functor; that functor must be converted to
        // boost::function1<void, i32> because the lambda functor
        // does not match the >> operator (your compiler yields ambigious
        // call if you try to pass the lambda functor itself).
        // Note: This functor does not print the received message to stdout.
        //       You'll see only the output of Ping if you run this example.
        acedia::Invoker i(on<GameBall>().unbox()
                          >>  boost::function1<void,i32>(var(hits) = _1));
        
        // Loop until we received a GameBall with hits >= 10
        while (hits < 10)
        {
            send(ping, GameBall(hits + 1));
            receiveAndInvoke(i);
        }
        
        std::cout << "Pong is done (normal exit)" << std::endl;
    }
};

int main(int, char**)
{
    // spawn a ping and register it as "ping"
    acedia::registerName("ping", acedia::spawn<Ping>());
    // spawn pong and ignore the return value of acedia::spawn
    (void) acedia::spawn<Pong>();
    // wait until game is over and shutdown
    acedia::waitForAllActorsDone();
    acedia::shutdown();
}

Generated by  doxygen 1.6.2