Wednesday, September 21, 2011

delayed_send

delayed_send and its brother delayed_reply are great if you need to poll a resource every x (milli)seconds while staying responsive to other messages or if you want to implement a "timed loop". Both accept std::chrono durations in seconds, milliseconds, microseconds and minutes. However, the accuracy depends on your scheduler, operating system, workload, etc., so you shouldn't rely on a microseconds-timing.

A good example for such a loop is an animation. In message oriented programming (and this is was libcppa is about), the most idiomatic way to implement such a loop is to send a message to yourself that is delayed by a predefined amount of time. If you receive that message, you do the next animation step and send another delayed message to yourself, and so on, until the animation is done.

Today's example is a terminal-animation with a dancing Kirby. Have fun!

#include <chrono>
#include <iostream>
#include <algorithm>
#include "cppa/cppa.hpp"

using std::cout;
using std::endl;
using namespace cppa;

// ASCII art figures
constexpr const char* figures[] = {
  "<(^.^<)",
  "<(^.^)>",
  "(>^.^)>"
};

// array of {figure, offset} pairs
constexpr size_t animation_steps[][2] = {
  {1,  7}, {0,  7}, {0,  6}, {0,  5}, {1,  5}, {2,  5}, {2,  6},
  {2,  7}, {2,  8}, {2,  9}, {2, 10}, {1, 10}, {0, 10}, {0,  9},
  {1,  9}, {2, 10}, {2, 11}, {2, 12}, {2, 13}, {1, 13}, {0, 13},
  {0, 12}, {0, 11}, {0, 10}, {0,  9}, {0,  8}, {0,  7}, {1,  7}
};

constexpr size_t animation_width = 20;

// "draws" an animation step: {offset_whitespaces}{figure}{padding}
void draw_kirby(size_t const (&animation)[2]) {
  cout.width(animation_width);
  cout << '\r';
  std::fill_n(std::ostream_iterator<char>{cout}, animation[1], ' ');
  cout << figures[animation[0]];
  cout.fill(' ');
  cout.flush();
}

void dancing_kirby() {
  // let's get it started
  send(self, atom("Step"));
  // iterate over animation_steps
  auto i = std::begin(animation_steps);
  receive_for(i, std::end(animation_steps)) (
    on<atom("Step")>() >> [&]() {
      draw_kirby(*i);
      // animate next step in 150ms
      delayed_send(self, std::chrono::milliseconds(150), atom("Step"));
    }
  );
}

int main() {
  cout << endl;
  dancing_kirby();
  cout << endl;
}

Tuesday, September 6, 2011

Timed Receive

It's not unusual to send a message and then wait for response. But if your communication partner doesn't reply, you'll wait forever. That's why we need an option to specify timeouts.

Here's a short example actor that does nothing but sends you back your own messages and exits if he idles for 10sec.

#include <chrono>
#include "cppa/cppa.hpp"

using namespace cppa;

void echo_server()
{
  receive_loop (
    others() >> []() {
      self->last_sender() << self->last_dequeued();
    },
    after(std::chrono::seconds(10)) >> []() {
      quit(exit_reason::user_defined);
    }
  );
}


The after()-statement has to be the last one and you can't specify more than one. An empty receive with nothing but a timeout should be used to sleep for a certain amount of time, e.g.:
receive(after(std::chrono::milliseconds(5)) >> []() {});

Btw: you should not use native sleep functions, because they are blocking. That's only ok if you spawned your Actor with the detached flag, because the Actor has its own thread in this case. But remember that your Actors usually share one thread pool and blocking function calls should be best avoided.