A process may wish to receive information from a subset of the set of ports available for receipt. Systems differ in the amount of selectivity provided to a receiving process. Some allow a process to receive either from a particular port or all ports. Others allow a process to specify any subset of the set of all ports. Still others allow a process to peek at the value of incoming messages and make its decision to accept or reject messages based on the contents of messages.
As we saw before, asynchronous receives allow us to declare our willingness to receive messages from multiple ports. A special select mechanisn is required to provide this flexibility with synchronous receives, which is illustrated below assuming language support:
select receive <port> ... receive <port> ... ... receive <port> ... end(We are assuming RPC here, with synchronous send) If none of the ports has a message, then the process blocks. If several ports have messages, then one port is chosen non-deterministically. If only one port has a message, then the corresponding receive is executed. Typically, a select is enclosed within a loop. Thus after servicing a request, a process can service another request.
Often a system allows a guard to be attached to an arm of the select. The guard is a boolean expression and the associated receive occurs only if the condition is true. The following example shows guarded receives in a `bounded buffer' process:
loop select when count > 0 receive consume (...) ... when count < size receive produce (...) ... end end loop.Here count keeps the number of filled buffers. The consuming process is blocked if the buffer is empty and the producing process is blocked if it is full.
A process executing such a loop statement is similar to a monitor (which we will study later.) Each receive in an arm of a select corresponds to an entry procedure declaration in a monitor (which we will study under process coordination). A process services one receive at a time, just as a monitor executes one entry procedure at a time. The guards correspond to waits on conditions. The Lauer and Needham paper contains a more detailed discussion on this topic.
In the example above we are assuming language-level support. Similar semantics can be supported through system calls.