MICA also provides a capability for synchronous communication between agents. This functionality is implemented as an optional additional layer on top of the asynchronous communications classes. Using this functionaliy, an agent can send a mob and wait for a reply to that mob. The mobs themselves are no different to any other mob. Rather, the process uses a specific slot to mark the return mob as being a reply to the original mob. This slot is called "replyTo" and its value is the id of the mob (or mobs) to which it is a reply. The synchronized transport layer uses the value of this slot when looking for a reply.
As with the asynchronous transport, the high-level interface
SynchronizedAgentActions
is quite simple. There is just one additional action
the agent can call. However, implementing this functionality is more complex as it involves both
an action and a message at the asynchronous level.
Figure 2.2 shows the flow of control for (a) synchronized messaging (b) the arrival of a normal message when a synchronized wrapper is in use. The steps involved in a synchromous action are:
The initiating thread generates a message inside the protocol and sends it, before block and waiting for a reply.
The parse thread is blocked and waiting for input
Input arrives from the blackboard
The input is parsed and found to be an action reply. The reply is stored and the initiating thread notified.
The initiating thread gets the reply and returns to the synchronized layer. It then blocks(again) and waits for a reply mob to arrive.
The XML parser thread is again block and awaiting input
More input arrives from the blackboard.
This input is parsed and found to be a message. It is passed to the queued handler.
The queued handler passes the message to the synchronous handler. Here it is determined that it is a reply to the mob originally sent by the initiating thread. The mob is stored as a synchronous reply and the initiating thread notified.
The initiating thread grabs the reply mob and passes it back to the agent.
The first five steps steps are the same as for asnychronous actions, it is only after the action reply is obtained the the process varies.
The synchronous wrapper must also ensure that any normal (non-reply messages) are still handled correctly. Again, the steps involved in this are similar to those for normal message handling:
the parser the thread is blocked and awating input.
Input arrives from the blackboard.
The input is found to be a message and is passed to the queued message handler.
The message handler passes the message to the synchronous layer. Here it is found that the message is not a reply to any sent messages, so it must be handled as a normal message. It is passed to a second queued handler inside the synchronous layer.
The synchronous queue handler behaves identically to the one in asynchronous layer, processing one message at a time in the order they arrive.
Several points worth noting in this process are:
Reply mobs are NOT handled like normal mobs - the agent's
handleNewMob
functions is never called for them.
It is possible that other messages will arrive between the initial action and the arrival of the reply mob. These mobs are handled like any other - they are added to the queue inside the synchronous layer and handled in the order they arrive. Of course, if the initiating queue is queuedMessageHandler thread (ie. the synchronized call was made from with one of the agents's message handler functions) then none of these mobs will be handled until after that message handling is complete
It is possible that no reply mob arrives. The synchronous calls have a timeout parameter and it is strongly recommended that be used to avoid having the thread block indefinitely while waiting for a reply that may not arrive.