Title: Channels
1Channels
- Processes in a concurrent system can communicate
by sending and receiving messages over channels - rather than reading and writing shared memory
- Model of arbitrary interleaving of atomic
statements still applies - not concerned with time
- relative order in which messages are sent and
received is important - Synchronous communication
- the exchange of a message is atomic
- a sender is blocked until the intended receiver
is ready to receive - the receiver is blocked until the sender is ready
to send - the send and receive actions of both processes
coincide
sender
receiver
message
2Channels
- Asynchronous communication
- A buffer is used to avoid blocking of senders and
receivers - When a sender sends a message, the message is
placed in a buffer - If there is space available in the buffer, the
sender continues execution and does not block - If the buffer is full, the sender blocks or a
message is lost - Receivers reads messages from the buffer
- Receiver only blocks if there is no data in the
buffer - Send and receive operations are not atomic and
may be arbitrarily interleaved with respect to
the execution of the receiver and sender
respectively
receiver
sender
message
buffer
3Declaring channels in Promela
- Promela supports both synchronous and
asynchronous channels - The size of a buffer for an asynchronous channel
can be defined - A channel with a buffer size of zero is
synchronous - Channels in Promela are typed
- Need to declare the type of the messages that are
sent and received - e.g. int, bool, bool a message containing an
integer and two bools - Synchronous Promela channel with integer messages
- Asynchronous Promela channel with buffer capacity
of ten and messages containing one int and one
bool
channel chsync 0 of int
channel chasync 10 of int, bool
4Channel operations in Promela
- Receiving messages from a channel
- receives the next message from the channel,
storing the message fields in the variables v1,
v2, ... - statement is executable if the variable list v1,
v2, ... matches the channel message type (e.g.
int, bool, bool) and if there is a mesage
available in the channel - otherwise, the statement blocks
- Sending messages to a channel
- sends the values val1, val2, ... over the channel
- statement is executable if there is an available
slot in the buffer - otherwise, the statement blocks
- can override blocking behaviour in Spin,
resulting in dropped messages
mychannel ? v1, v2, ...
mychannel ! val1, val2, ...
5Dining philosophers with channels
- Both philosophers and forks are modelled as
processes - A philosopher process repeatedly
- receives its left fork, followed by its right
fork (or vice versa) over channels from the fork
processes, blocking until they are available - eats
- sends the left and right forks back to the
respective fork processes - A fork process repeatedly
- sends out a fork (to anyone that wants it)
- blocks until the fork is returned
- What will an analysis using Spin/Promela show us?
- Deadlock arises for the same reasons as before
- (remember 4 necessary and sufficient conditions
for deadlock) - We can resolve the deadlock using similar
techniques as before
6Deadlock-prone philosophers with channels
chan forks4 0 of bool proctype
Phil(byte n chan left chan right ) do
left ? _ right ? _ printf("MSC d
eating, total d\n", n, numEating) right !
true left ! true od proctype Fork(chan
ch) do ch ! true ch ? _ od init
atomic run Fork(forks0) run
Fork(forks1) run Fork(forks2) run
Fork(forks3) run Phil(0, forks0,
forks1) run Phil(1, forks1, forks2)
run Phil(2, forks2, forks3) run Phil(3,
forks3, forks0)
Simulation using Spin/Promela?
Analysis using Spin/Promela?
7Deadlock-free philosophers with channels
chan forks4 0 of bool proctype
Phil(byte n chan left chan right ) do
left ? _ right ? _ printf("MSC d
eating, total d\n", n, numEating) right !
true left ! true od proctype Fork(chan
ch) do ch ! true ch ? _ od init
atomic run Fork(forks0) run
Fork(forks1) run Fork(forks2) run
Fork(forks3) run Phil(0, forks0,
forks1) run Phil(1, forks1, forks2)
run Phil(2, forks2, forks3) run Phil(3,
forks0, forks3)
Simulation using Spin/Promela?
Analysis using Spin/Promela?
8Deadlock-free philosophers with channels
- Could also implement the butler solution over
channels - Butler supplies an eat token to requesting
processes over a channel - Philosopher can only acquire forks when it holds
an eat token - After releasing forks, a philosopher will return
the eat token (either to the butler, or to
another philosopher)
chan forks4 0 of bool chan butler
4 of bool proctype Phil(byte n chan
left chan right ) do butler ? _ left
? _ right ? _ printf("MSC d eating, total
d\n", n, numEating) right ! true left !
true butler ! true od proctype Fork(chan
ch) do ch ! true ch ? _ od
9Deadlock-free philosophers with channels
proctype Butler(byte n chan ch) byte count
n - 1 do (count 0) ch !
true count-- ch ? _ count od
init atomic run Butler(4, butler)
run Fork(forks0) run Fork(forks1) run
Fork(forks2) run Fork(forks3) run
Phil(0, forks0, forks1) run Phil(1,
forks1, forks2) run Phil(2, forks2,
forks3) run Phil(3, forks3,
forks0)
Simulation using Spin/Promela?
Analysis using Spin/Promela?
10Rendezvous communication
- Rendezvous or request-reply is a message-passing
protocol used to support client-server
interaction - Many-to-one communication between clients and a
service - Only one client is serviced at a time
rescall(entry,req)
request message
reqaccept(entry)
reqaccept(entry)
service request
reply(entry,res)
reply message
11Rendezvous in Promela
- A synchronous channel for requests
- A per-client (or per-request) channel for
receiving the response
chan entry 0 of chan, int active
proctype Server() chan cli int n do
entry?cli, n cli!n2 od active
4 proctype Client() int res chan mychan
0 of int entry!mychan, _pid mychan?res
12Selective receive
- In promela, it is possible to block waiting for
input on multiple channels - The same behaviour is harder to achieve in
languages such as Java or C/C - Solutions?
if chan1 ? x - / do something
/ chan2 ? x - / do something else
/ chan3 ? x - / something else again
/ fi
socketA.read() socketB.read() socketC.read()
want any one of these blocking calls to execute