Consider two tasks that wish to communicate: task E and task F. Task E is a time sensitive task that needs to deliver a package of data to task F. Task E cannot take the chance that task F will accept its data immediately and issue a reply so that it may continue with its own jobs. In short, a synchronous send compromises task E's job because it must wait for task F to respond before proceeding.
To send data asynchronously from task E to task F, a queue is used. Data is sent from task E to the queue. The queue responds immediately to task E, freeing it up to continue. Then a proxy, a special non-blocking message, is sent from the queue to task F. Upon receipt of the proxy, task F knows that the queue contains data for it. When task F is ready it asks the queue for the data.
With some small changes, the example from the previous section can be changed from synchronous messaging to asynchronous, as follows:
Task E:
#!/usr/cogent/bin/gamma
init_ipc("task_e","task_e_q");
add_set_function(#x,#princ("Task E reports x=",x,"\n"));
while (t)
{
next_event();
}
Task F:
#!/usr/cogent/bin/gamma
init_ipc("task_f","task_f_q");
function inc_x ()
{
local result,tp;
x++;
if (tp = locate_task("task_e",nil))
{
result = send_async(tp,list(#setq, #x, x));
princ("task F result of send: ",result,"\n");
}
}
x = 0;
every(0.1,#inc_x());
while (t)
{
next_event();
}
The init_ipc function calls at the beginning of
each module now open a queue name with qserve, and
the inc_x function has been changed to use
send_async instead of
send.
When this example is run the results show that task
F receives a t (true) that the message was
delivered but does not have to wait for task E to
generate the result of the expression.
Using asynchronous communication immediately solves the dead-lock
problem that all developers of multi-module systems must eventually
face. To the developer, the use of asynchronous communication in Gamma
entails only the use of a slightly different function:
send_async instead of
send.