Archive for the tag 'blackboard'

Access Blackborad With Timeout

Operations that access a blackboard to retrieve information, i.e. operations read and take, have a second parameter that defines how long should this operation wait until there will be a matching n-tuple or, simply, timeout. A value of the parameter specifies number of second.

Example:

  • To read a tuple and if there is no such tuple, to wait 4 seconds for it:
    ts.read [nil, nil], 4
    
  • Or to take a tuple and if there is no such tuple, to wait 1 minute for it:
    ts.take [nil, nil], 60
    

There are two special values that you may use as a timeout value:

  • 0 (zero) - an operation would not wait at all. It is useful for checking, if a n-tuple is stored in the blackboard or not.
  • nil - an operation would wait endlessly. Of course, there is not difference if you would call an operation without a specified timeout value or with nil.
    Actually, to be more precise, an operation would wait 231 - 1 seconds, that is approximately 30 years. ;)

But what would happen, if we specify a timeout value and an n-tuple would not appear on the blackboard in the specified time(out)?
Rinda throws the Rinda::RequestExpiredError exception.

The handling exceptions in Ruby is very comfortable (esp. with the command retry). An example follows, where a tuple is taken with a timeout 5 seconds. This allows to inform an user about the state, that the application is still waiting for a message:

puts "Waiting for a message."
begin
  t = ts.take [:message, nil], 5
rescue Rinda::RequestExpiredError
  puts “Still waiting for a message.”
  retry
end

The timeout functionality allows to:

  • create a responsiveness application - to inform other components or users about its state (e.g. waiting for a message - processing a message).
  • end an application normally - to break waiting for a n-tuple every so often and check if the application should end.
  • check for different n-tuples - it is possible to wait in deferent intervals for different n-tuples. Of course, a better solution is to create for each n-tuple an own thread that performs a blackboard access operation for this particular n-tuple.
  • create an application that does not access a blackboard all the time (e.g. only every hour for 1 minute).

Read Message On Blackboard

To finish the overview of the backboard operations, let’s show how to use the read operation. It only checks, if a blackboard contains a wanted tuple (in the previous posts I used the term message, but now we are more experienced :).

The following functionalities will be shown:

  • Creation of an agent.
  • Locating the blackboard.
  • Read a message.

The agent source code is stored in the read.rb file:

require 'rinda/ring'

DRb.start_service

ts = Rinda::RingFinger.primary

result = ts.read [:message, nil], 0

puts “[0]: #{result[0]}”
puts “[1]: #{result[1]}”


See a screencast Read message on blackboard screencast [.ogg].

Firstly, start the rinda.rb code (for more details see the post about starting multi-agent system environment), then, in a separate console, start the write.rb (for more details see the post about writing a message to the blackboard) and finally, in a separate console or in the same console where you started the write.rb file, type:

ruby read.rb

The agent connects to the blackboard, reads a tuple and shows two lines:

[0]: message
[1]: Hi there!

Of course, you could repeat this step any number of times, because this operation only checks if a tuple is there.


Files to download: rinda.rb, write.rb and read.rb.

Take Message From Blackboard

The Rinda multi-agent system environment is already running, on the blackboard is written a message, so the last step is to read it :)

The following functionalities will be shown:

  • Creation of an agent.
  • Locating the blackboard.
  • Taking a message.

Although a logical opposite operation to the write operation should be the read operation, it is not so in the blackboard system: the operation read only checks if a message is there (this will be shown in a post that will follow); the operation take takes a message from the blackboard.


The agent source code is stored in the take.rb file:

require 'rinda/ring'

DRb.start_service

ts = Rinda::RingFinger.primary

result = ts.take [:message, nil], 0

puts “[0]: #{result[0]}”
puts “[1]: #{result[1]}”


Firstly, start the rinda.rb code (for more details see the post about starting multi-agent system environment), then, in a separate console, start the write.rb (for more details see the post about writing a message to the blackboard) and finally, in a separate console or in the same console where you started the write.rb file, type:

ruby take.rb

The agent connects to the blackboard, takes a message and shows two lines:

[0]: message
[1]: Hi there!


Files to download: rinda.rb, write.rb and take.rb.

Write Message To Blackboard

The Rinda multi-agent system environment is already running, so the next step is to write a message to the blackboard with an agent.

The following functionalities will be shown:

  • Creation of an agent.
  • Locating the blackboard.
  • Writing a message.

The agent source code is stored in the write.rb file:

require 'rinda/ring'

DRb.start_service

ts = Rinda::RingFinger.primary

ts.write [:message, 'Hi there!']

puts ‘Message was sent.’


Firstly, start the rinda.rb code (for more details see the post about starting multi-agent system environment) and then, in a separate console, type:

ruby write.rb

The agent connects to the blackboard and writes a message Hi there!.


Files to download: rinda.rb and write.rb.


For running more processes it is necessary to open more consoles. Applications like screen or konsole on KDE can help you — I use konsole with more sessions.

Starting Multi-Agent System Environment

By starting the Rinda multi-agent system environment we will start the following functionalities:

  • Blackboard. Agents will be able to access a shared place for messages.
  • Discovery service. Agents will be able to find the blackboard automatically.

The whole multi-agent system environment can by started from one file, let’s call it rinda.rb:

require 'rinda/ring'
require 'rinda/tuplespace'

DRb.start_service

ts = Rinda::TupleSpace.new
Rinda::RingServer.new ts

puts 'The blackboard is started...'

DRb.thread.join

Of course, the name can be different :), but in the future examples we will refer to it as the rinda.rb file.


The environment can be started with following line:

ruby rinda.rb

After a start, the message The blackboard is started… appears and the system fully started and ready to serve. :)


Files to download: rinda.rb.

Blackboard Operations

A blackboard system should support three operations: write, take, read.

  • write — adds a message to the blackboard.
  • take — returns a content of a message from the blackboard, but it also removes it from the blackboard. An agent, that performed the take operation, is the only one in the system, that has a content of this message.

    This operations is usually used for messages that start a task. There is no need to let other agents to start the same task.

  • read — returns a content of a message from the blackboard. The message stays there, so other agents can also read a content of this message.

    This is used for messages that describe a state of the whole system — a flag. For example, a flag stop processing should be visible to all agents, so all of them will stop processing.

Multi-agent System in Ruby

To build a (simple) multi-agent system, we need at least three functionalities: communication between processes, discovery service and blackboard.

Let’s explain each functionality and show how it is provided in Ruby:

  • Communication between processes. Agents need to communicate with the rest of the world. Otherwise, it will not be possible to say them, what they should do and we will not know, what they did, because they did not present their results. ;) In the previous post, we said that agents are, from the operating system point of view, processes; technically we need a communication between processes.

    This functionality is provided by the Distributed Ruby library. You can find two abbreviations: DRb, dRuby. Both of them refer to the same library..

  • Discovery service. An agent should be able to automatically find other agents or a blackboard.

    This functionality is provided by the Rinda library, by its class Ring.

  • Blackboard. A blackboard is a shared place for exchanging data. It has to comply with the following important requirement: atomic access. What does it mean? If one agent takes a message, another agent should not be able to take the same message, so it will not happen that two (or more) agents received the same message.

    It is provided by the Rinda library, by its class TupleSpace.

Good news: distributed Ruby and Rinda are included in Ruby 1.8. :)

Ruby on Blackboard

The most usual way how to build an application is to create a monolithic system.

The code inside may vary in complexity - from straightforward, a few conditions, to complex with threads.

The next level of complexity is to spread an application into more processes. Communication between processes is more complicated then between threads and usually there is a special layer dedicated to this, e.g. DRb in Ruby or RMI in Java.
And we are only a short remove from a possibility to communicate between processes on different computers. Often the dedicated layers handle this complexity level too.

But on both sides, there are still monolithic sytems, that are only deployed on different computers.

The dialog between processes looks like this:

A: I want to load data with Process 1 on the computer 192.168.0.45.
B1: No response. It seems that the process is busy.
A: I want to load data with Process 1 on the computer 192.168.0.73.
B2: John, 34 years old, London. Susanne, 25 year old, Stockholm.

What would you say, if a situation would look like this?

A: Writes a message “Please, can you send me data?” on a blackboard.
B1: Is busy, so it does not have time to check the blackboard.
B2: Is available, so it erases the messages (to not to bother others with it) and writes the data on the blackboard - John, 34 years old,

What is the difference?

  • In the first situation the communication is pointed and forced. If the answering process is busy, the requesting process has to wait or find another answering process. It has to act actively until a request is transfered.
  • In the second situation, processing are taking tasks, if they are available. The communication is not pointed and forced. The request process does not have to take care about the posted message.

You probably noticed a special word in the second situation - blackboard. It is a shared place for exchanging messages. It allows to post, check for and delete a message.

Applications A, B1 and B2 are autonomous applications performing a task; usually it is a specialised task, so the application is small and simple. These applications are called agents.

An environment that allows to execute agents and provides various functionality such as communication between agents or coordination is called a multi-agent system. (Sorry for a simplification.)

On this blog, you will find how to create agents, coordinate them, how to solve their problems and how to solve problems with them. Oh, I would forget: in Ruby! :)

Welcome to the Ruby Agent a.k.a. Ruby on Blackboard blog :)