Lab 5

advertisement
COMP60621 Lab Exercise 5
Aim: This exercise is designed to illustrate the use of Promela-based modelling in the
design phase of a software project. The exercise focuses on issues related to correct
termination in concurrent systems.
The source code and other files required for this exercise may be found in directory
~griley/COMP60621/source/labs/lab5. Make a new directory for this lab, and copy
these files into it.
The recommended form for submission of answers is by email to
graham.riley@manchester.ac.uk (the submitted file must be a pdf file - no other
electronic format is acceptable). Reports should have a maximum length of three
pages. Supporting material, such as fragments of code and/or Promela, can be
included in a brief appendix. Submission deadline: 9.00am Tuesday 4th December
2012.
1. A Supervisor-Worker example implemented using a Tuple Space.
A tuple space is an implementation of an associative memory for parallel and
distributed systems. A repository of tuples is maintained and the repository supports
concurrent access. A tuple is essentially a tagged data record and the tag identifies the
class of data in the tuple. Tuple spaces were the theoretical underpinning of the Linda
language developed by David Gelernter and Nicholas Carriero at Yale in the late
1980s. This example illustrates a very basic tuple space that supports the following
simple operations:
i. out(“tag”, value) to place a tuple of type ‘tag’ in the tuplespace.
ii. in(“tag”, data) to retrieve (and delete) a tuple from the tuplespace. This
operation ‘blocks’ until a tuple of the requested type is available.
iii. rd(“tag”, data) to retrieve, without deleting, a tuple from the
tuplespace. This is also a blocking operation.
iv. inp() and rdp() are polling (i.e. non-blocking) versions of in() and rd()
operations. They return true, along with the tuple, if a matching tuple is
found and false otherwise.
(In a full implementation of a tuple space, the matching process involved in ‘in’ and
‘rd’ operations is much more sophisticated. In general, the ‘data’ in a tuple is allowed
to be a list of items. Some of the items can be explicit values specified by the caller
that must match the content of any tuple to be returned to the caller, whereas the other
items represent variables to contain the ‘return’ values of data items not specified by
the caller.)
The application implemented in the supervisor-worker example code is a simple
numerical integration of a mathematical function. An approximate value of the area
under a curve is generated using the rectangle method. This involves splitting the xaxis into a number of partitions and summing the areas of each of the resulting
rectangles under the function curve. The area of a rectangle associated with a given
partition along the x-axis is determined from the size of a partition (all partitions are
the same size) and the function value at the midpoint of the partition.
In the example Promela model we will examine, the supervisor initially places a
number of tuples tagged as task tuples into the tuplespace. Each task tuple represents
one of the partitions along the x-axis. Workers repeatedly remove task tuples from the
tuplespace, process them and return a result tuple to the tuplespace. The supervisor,
meanwhile, removes result tuples and adds their value to the final result. Ensuring
correct termination of the supervisor and the workers is one of the difficulties in
designing and implementing the tuplespace application.
The Promela file TestTuple.pml contains a model of a tuple space along with a
process that accesses the tuplespace sequentially. You may find it useful to use jSpin
to get a feel for how the tuplespace works by, for example, adding and/or modifying
statements to access the tuplespace.
The Promela file SupervisorWorker_1-full.pml contains models of the tuplespace and
of the supervisor and worker processes. A system consisting of a single supervisor
and two workers is constructed. This example implements a plausible-looking
termination algorithm that is, in fact, flawed. The algorithm implemented in this
version is as follows:
Supervisor:
forall tasks: out(“task”,…)
forall results: in(“result”,…)
out(“stop”)
end
Worker:
While not rdp(“stop”) do {
in(“task”,…)
Compute result
out(“result”,…)
}
End
In the Promela file, the operations on the tuplespace are implemented in terms of
Promela channels.
a) Run and Verify the model in jSpin. Note that jSpin finds a deadlock.
Consider the program from both the perspective of the operations on the
tuplespace (in(), out() and rdp()) and, separately, from the channel-based
level used in the implementation of the operations. At each of these levels,
describe the origin and nature of this deadlock in terms of the behaviour of
the component processes in the model and, hence, informally explain the
‘fault’ in the algorithm. [Hint:You may find it useful to use Guided mode
in jSpin to examine the error trail produced by jSpin. You may also find it
useful to start at the end of the trail and work backwards to see how the
processes arrived at the final, deadlocked state.]
The C code for the supervisor-worker example is intended to implement the design
contained in the Promela file SupervisorWorker_1-full.pml. In this example, the only
operations supported in the C code are in(), out() and rdp(). In the C code, these
operations are implemented in terms of Pthreads and pthread condition variables.
b) Briefly describe the use of pthread condition variables in implementing the
operations of the tuplespace.
c) Compile the code (the instructions are contained in the header of the file
supervisor_worker.c). Execute the code a few times and confirm that the
code does indeed exhibit deadlock. Report approximately how frequently
does deadlock occurs. Explain how the deadlock arises in the code in
terms of pthread functions. (Hint: focus on the use of pthread condition
variables and of the pthread join function in the code) and describe the
deadlock situation in the terminology of the ‘four conditions for deadlock’
[Hint: in this case, the shared resources may not be immediately obvious.
Once deadlocked, consider what each thread is actually waiting for, and
why.]
d) Comment briefly on the correspondence between the channel-based
implementation of the tuplespace operations in Promela and the pthreadbased implementation of the operations in the C code. Do you think the
two implementations provide equivalent behaviour for the tuplespace
operations (for our purposes – that is, for investigating termination
behaviour)? [Hint: consider how each implementation provides the
wait/notify functionality required of the operations.]
2. A correct termination algorithm
One relatively simple termination algorithm for problems such as this is known as the
‘poison pill’ algorithm. In one version of this algorithm, the supervisor places ‘poison
pill’ task tuples in the tuplespace, one for each worker. A ‘poison pill’ task tuple is a
task with a special value. A worker continues taking tasks from the tuplespace until a
‘poison pill’ task is found, in which case the worker terminates. An algorithm for this
version might be:
Supervisor:
forall tasks: out(“task”,…)
forall results: in(“result”,…)
forall workers out(“task”, stop)
end
Worker:
While true do {
in(“task”,…)
if value is stop then
exit
else
Compute result
out(“result”,…)
}
end
a) Describe the modifications required to the Promela models of the
supervisor and workers to implement this version of the ‘poison pill’
algorithm. (Hints: What is a suitable special value for a ‘poison pill’ task?
How should the supervisor and worker processes be modified to use this
value?) Modify the Promela to include this algorithm and check that jSpin
confirms that the improved model is deadlock free.
b) Implement the algorithm in the C code. Undertake some testing to check
that the code now terminates correctly. (Hint: The supervisor will need to
know how many workers there are.)
c) An alternative implementation of the ‘poison pill’ algorithm requires the
supervisor to output only a single ‘poison pill’ task. For correct
termination, when a worker finds this task, it must place a ‘poison pill’
task back into the tuplespace before terminating (why?). Design and
describe a version of this algorithm and implement it in both the Promela
and the C code.
3. Critical Section Problem and liveness properties
This section uses Promela source code that was seen in Lab exercise 3.
a) Construct a version of a Promela model that implements attempt 1 of the
solution to the Critical Section Problem. Include in your model of one of
the processes the code implementing a non-progressing non-critical
section, as discussed in the lectures. Use jSpin to verify that this version of
the model is not free from starvation. Briefly describe the technique you
employed in using jSpin, including any additions you made to the model
code and any properties and verification modes you used in jSpin. Also
report the resulting output from jSpin. Informally describe how the
starvation arises, with reference to the output reported by jSpin.
b) Implement the same non progress non-critical section code in a version of
the (allegedly correct) Dekker’s algorithm. Report the results of a
verification of freedom from starvation in jSpin. Very briefly, describe
how Dekker’s algorithm avoids the starvation present in attempt 1.
Download