Recall that the need for asynchronous communication can arise when the tasks involved in a computation must access elements of a shared data structure in an unstructured manner (Section 2.3.4). One implementation approach is to encapsulate the data structure in a set of specialized data tasks to which read and write requests can be directed. This approach is easily implemented using FM constructs: for example, the process structure illustrated in Figure 6.4 could be used to connect four computation tasks with three data tasks.
An alternative implementation approach is to distribute the shared data structure among the computation tasks. Individual computation tasks must then poll periodically for pending read and write requests. This approach is supported in FM by the PROBE statement, which allows a process to determine whether messages are pending on the channel or merger associated with an inport. This is a potentially nondeterministic operation, since the result returned by a PROBE statement can vary depending on the time at which it is executed. A PROBE statement has the general form
PROBE( inport, empty= logical )
and sets the logical variable named by the empty specifier to true if the channel is empty (meaning a RECEIVE on the inport would block) and to false otherwise.
Optional iostat= and err= specifiers can be included in the control list; these are as in the Fortran inquire statement. Hence, applying a PROBE statement to an undefined port causes an integer variable named in an iostat specifier to be set to a nonzero value and causes execution to branch to a label provided in an err= specifier.
Knowledge about send operations is presumed to take a nonzero but finite time to become known to a process probing an inport. Hence, a probe of an inport that references a nonempty channel may signal true if a value was only recently communicated. However, if applied repeatedly without intervening receives, PROBE will eventually signal false and will then continue to do so until values are received.
The PROBE statement is useful whenever a process needs to interrupt local computation to handle communications that arrive at some unpredictable rate. For example, the following code might be used in an implementation of the branch-and-bound search algorithm of Section 2.7.
inport (T) requests ! T an arbitrary typelogical eflag
do while (.true.) ! Repeat:
call advance_local_search ! Compute
PROBE(requests,empty=eflag) ! Poll for requests
if(.not. eflag) call respond_to_requests
enddo
This code fragment alternates between advancing a local search and responding to requests for search problems from other processes.
The PROBE statement can also be used to receive data that arrive in a nondeterministic fashion from several sources. For example, Program 6.7 handles messages of types T1 and T2 received on ports data1 and data2, respectively. A disadvantage of this program is that if no messages are pending, it consumes resources by repeatedly probing the two channels. This busy waiting strategy is acceptable if no other computation can be performed on the processor on which this process is executing. In general, however, it is preferable to use a different technique. If T1=T2 , we can introduce a merger to combine the two message streams, as follows. The handlemsgs2 process then performs receive operations on its single inport, blocking until data are available.
MERGER(in=datai, out=data1o, out=data2o) PROCESSES PROCESSCALL source1(data1o) PROCESSCALL source2(data2o) PROCESSCALL handlemsgs2(datai) ENDPROCESSES
© Copyright 1995 by Ian Foster