In the displayed network, the first cells retain values and cell is still in its initial state. It accepts only a value in , so it cannot accept the incoming sentinel value. For the first cell blocks the external sentinel value; for a stored cell blocks while trying to pass it to an empty neighbour. ThusTo handle shorter inputs, add an empty-cell branch to the initial state. An empty cell then terminates the downward scan and immediately returns an empty sequence. Earlier occupied cells append their retained values exactly as before; later cells need not participate. This works for every , because the occupied prefix of the chain alone produces the required output. For , the original sentinel-only tail still supplies the empty suffix. Every cell receives the same modification.
Past exam of the computer science course of the University of Oxford 2015 Concurrency 1 d i Solution 2026-10-31
Use a chain of identical storage cells, each retaining the first value it sees and passing later values to the next cell. On the return journey it passes the next cell's reversed output before emitting its own retained value. This turns the chain into a distributed LIFO stack.
Here is one cell template. Its ports carry incoming values towards the tail; carry returning values towards the front. Each port carries values in , with the sentinel value outside :An input such as abbreviates an indexed CSP external choice over the corresponding CSP events. An output is the CSP prefixing action . There is no extra controller process.
For , take copies of this same template. Introduce channels for and apply port CSP event renaming to copy , for , as follows:At the front put and . Adjacent cells synchronize on every shared or CSP event. The two tail channels are sentinel-only: and are local tail CSP events, with no other participant required. Disable all for . Formally, use a partial relational CSP event renaming for the last copy, omitting the pairs for its with ; an unmapped transition is blocked. This explicitly prevents a fictitious tail from generating data.
Let be the resulting port-renamed cell and its visible alphabet. With consisting of the internal link CSP events, including the two tail CSP events, the answer isHere the indexed operator is CSP alphabetized parallel composition: each CSP event is synchronized by all cells whose alphabets contain it. There are exactly storage-cell processes; port wiring and the sentinel-only tail adapt their interfaces, without adding a helper process. The local tail CSP events are hidden, as are all inter-cell communications.
To see correctness, after inputs have propagated, cell retains . The input sentinel value propagates to the tail. The last cell performs its two local tail CSP events, then returns . Inductively, if the suffix after cell returns , cell relays those values, replaces the final sentinel value by , and stops. Hence the external output isand starts only after . Shared links provide synchronization rather than an assumption that all cells take steps simultaneously. For the degenerate known-empty input, no storage is needed: the interface is simply .
Follow the next reference for the desired level, stopping at the tail. This returns the genuine nodes in their linked list order, excluding both sentinel nodes.Write for the resulting sequence of nodes at level . The abstraction function isIt preserves repetitions, because distinct nodes may carry equal values. A suitable representation invariant requires the following:
def nodesAt(level: Int): List[Node] = {
require(0 <= level && level < NumLevels)
val out = scala.collection.mutable.ListBuffer.empty[Node]
var n = head.nexts(level)
while (n ne tail) {
out += n
n = n.nexts(level)
}
out.toList
}headandtailare distinct sentinel nodes with the specified extreme values; every node has anextsarray of lengthNumLevels.- For each level, following references from
headgives a finite acyclic chain ending attail, thennull; the data along that chain are nondecreasing. Genuine values lie strictly between the sentinel values. - Each is a subsequence of by node identity, so the relative order of equal-valued nodes agrees across levels. Every genuine node occurs in and on a contiguous initial collection of levels.
- A genuine node absent from a level has
nullin that level's slot. Tail slots are allnull; every other slot on a chain points to the next member of that chain.