Example 04 – Operations with guards


When defining an operation, a guard can be specified as a condition that must be verified to start operation execution, otherwise such execution is suspended. This can be done by including a guard attribute in the @OPERATION annotation, specifying the name of the boolean method (guard method) – annotated with @GUARD, representing the condition to be tested. Guard methods are called passing the same parameters of the guarded operation (so they must declare the same parameters). Typically guard methods do checks on the value of internal and observable state of the artifact, without changing it. Operations with guards are useful to realise artifacts with synchronisation functionalities. In the following example, guards are used to implement a bounded buffer artifact in a producers-consumers architecture.

MAS example04_prodcons {

    environment:
    c4jason.CartagoEnvironment

    agents:
    producer agentArchClass c4jason.CAgentArch #10;
    consumer agentArchClass c4jason.CAgentArch #10;

    classpath: "../../../lib/cartago.jar";"../../../lib/c4jason.jar";
}

Ten producers agents and ten consumers agents exchange information items by exploiting the bounded buffer. Guarded operations allow for realising a simple coordinated behaviour, such that consumers’ get action is suspended if the buffer is empty, and producers’ put action is suspended if the buffer is full. Bounded buffer code:

public class BoundedBuffer extends Artifact {

  private LinkedList

Producers code:

item_to_produce(0).

!produce.

+!produce: true <-
  !setupTools(Buffer);
  !produceItems.

+!produceItems : true <-
  ?nextItemToProduce(Item);
  put(Item);
  !!produceItems.

+?nextItemToProduce(N) : true
 <- -item_to_produce(N);
    +item_to_produce(N+1).

+!setupTools(Buffer) : true <-
  makeArtifact("myBuffer","c4jexamples.BoundedBuffer",[10],Buffer).

-!setupTools(Buffer) : true <-
  lookupArtifact("myBuffer",Buffer).

Consumers code:

!consume.

+!consume: true
  <- ?bufferReady;
     !consumeItems.

+!consumeItems: true
  <- get(Item);
     !consumeItem(Item);
     !!consumeItems.

+!consumeItem(Item) : true
  <- .my_name(Me);
     println(Me,": ",Item).

+?bufferReady : true
  <- lookupArtifact("myBuffer",_).
-?bufferReady : true
  <-.wait(50);
     ?bufferReady.

Highlights:

  • Operation execution resume: When an agent executes a guarded operation whose guard is false, the operation execution is suspended until the guard is evaluated to true.
  • Mutual exclusion: Mutual exclusion and atomicity are enforce, anyway a suspended guarded operation is reactivated and executed only if (when) no operations are in execution.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>