Chapter 34 / 36

Project: a two-station line

Design buffers, ownership and recovery across concurrent stations.

Four-phase request and acknowledgement exchange that transfers one item across a station boundary
A successful exchange is only one case. Add a communication interruption after each numbered arrow. Write who owns the physical item before deciding what the restarted controllers may do.

Now let both stations execute independently. A may finish a scan while B is still processing old network data. Your contract must survive that ordinary scheduling difference. Use the project below to test a stronger question than “does it transfer?”: can both sides agree on the same item after a timeout, reset or interrupted acknowledgement?

Two correct stations can form an incorrect line

Station A processes a carrier, then waits for B to receive it. Station B is empty, but waits for A to announce that transfer has finished before it reserves its input. Both local programs look reasonable. Neither can move.

This is a coordination problem. Our training line has two independently controlled stations and a single-carrier transfer zone. A processes for three seconds, B processes for five, and the zone moves one carrier at a time. The values make waiting visible; they are not production targets.

We will design the agreement between stations before their internal code. The central questions are who owns the carrier, who owns the shared zone, and what evidence changes either ownership.

Draw resources separately from states

There are three resources: A's nest, the transfer zone, and B's nest. A state called WaitingForB describes A's behavior; it does not reserve B's nest. Keep resource availability and transaction ownership explicit.

At any moment, the zone is Free, Reserved for a particular transfer, Occupied by that transfer, or Uncertain. “Uncertain” is important after interruption. A false occupancy sensor does not necessarily prove an empty zone if its data is invalid or the carrier lies outside its detection area.

For the first model, an arbiter in the line controller owns the shared zone. Stations request transfers; they do not write each other's state variables. This is not the only possible architecture, but it creates one visible place where resource grants are decided.

Define a reservation transaction

Use a monotonically changing transaction identifier within the model session. The interface has four meaningful stages:

StageA's obligationB's obligationZone owner
RequestHold carrier and identify offered workReport ability to reserveArbiter keeps zone free
AcceptedPreserve offered transactionReserve its destination for that transactionArbiter grants matching transaction
TransferMove only under matching grant and permissionPreserve reservation and observe receiptArbiter marks occupied
ConfirmedRelinquish carrier after agreed evidenceAccept carrier identity exactly onceArbiter releases after clear evidence

The sender clearing its source sensor is evidence of departure, not necessarily proof of arrival. The receiver's presence sensor proves a physical observation, not by itself the identity of the carrier. The transaction links those observations under the model's one-carrier and spacing assumptions.

Keep readiness and commitment distinct

B may advertise readiness while empty. Once it accepts transfer 62, it withdraws general readiness to prevent another offer. That withdrawal must not cancel transfer 62. B is now committed to the accepted transaction.

Cancellation needs its own contract. Before movement, a reservation may be cancelled through a defined acknowledgement. During movement, cancellation may produce an interrupted transaction requiring reconciliation. A station must not silently forget a reservation because a generic Ready bit changed.

For each message, define persistence. A request remains visible until acknowledged or cancelled; it is not a one-scan pulse that the other task can miss. Duplicate messages bearing the same identifier should preserve the same transaction rather than creating another transfer.

Recognize a circular wait

Deadlock needs more than slowness. A useful diagnostic is a wait-for graph: draw an arrow from a participant to the resource or decision it needs. If A holds the zone while waiting for B's nest, and B holds its nest reservation while waiting for the zone to become free, neither condition can become true.

Avoid this model deadlock by reserving the required destination and zone together before beginning movement. The arbiter grants only when both are available. If all resources cannot be granted, A keeps its carrier in its own nest and holds no partial transfer reservation.

Other systems use a consistent acquisition order or more elaborate scheduling. The choice must fit the process. Adding a timeout that clears all ownership is not a general solution: it can make the software appear free while a carrier remains physically in the zone.

Separate liveness from mutual exclusion

Mutual exclusion means two transfers never own the same zone simultaneously. Liveness means accepted work eventually progresses or receives an explained failure outcome. A program can satisfy the first by never granting anything, which is perfectly exclusive and completely useless.

Write both kinds of requirements. For this model, only one active transaction can own the zone. A continuously eligible request should receive a grant when the required resources become available under the scheduler's defined policy. An accepted transfer must complete or become explicitly interrupted within its supervision limit.

If two upstream stations later share the zone, define fairness. Always preferring the lower station number can starve another station. A rotating priority or oldest-request policy may help, but test its behavior under unequal cycle times and blocked destinations.

Recovery needs a reconciliation table

After power loss, the logical transaction may be gone while the carrier remains. Do not reconstruct ownership from a single sensor without stating the assumptions. Use a recovery table reviewed for the actual machine; our model uses these learning cases:

A presentZone presentB presentModel recovery decision
YesNoNoKeep carrier at A; require fresh transaction
NoYesNoMark transfer uncertain; guided model reconciliation
NoNoYesReconcile B carrier identity before processing
YesYesYesReject automatic recovery; inconsistent with one-carrier exercise

Sensor validity is a prerequisite for using this table. A missing communication update is not equivalent to an empty nest. The recovery workflow also checks transaction records and permits an authorized product-disposition decision where identity cannot be recovered.

Observe concurrency in the model

Run A and B with independent control updates and add adjustable message delay. You should see A process the next carrier while B works, provided the buffer arrangement allows it. When B takes longer, A eventually waits for capacity; that is expected blocking, not necessarily a defect.

Trace request identifier, accepted identifier, zone owner, physical occupancy, receipt confirmation, and completion acknowledgement. Inspect the trace when communication is delayed or duplicated. The protocol should be understandable without relying on both stations evaluating in one lucky order.

Try it

A transfer is accepted. The carrier leaves A and reaches B, but the acknowledgement to A is lost. A times out and sends the same request again. The current receiver treats every request as new work. Explain the duplicate-work risk and design a recovery-safe response for the model.

Work through the answer

B already owns the carrier but could create a second record or run processing twice when the repeated request arrives. A timeout tells A that confirmation is missing; it does not prove that transfer failed physically.

B must recognize the repeated transaction identifier and return the known outcome rather than accept a second carrier. A should distinguish an unknown outcome from a confirmed failed transfer. Preserve enough transaction history for the agreed retry and restart window, and define what happens when that history is unavailable.

Test a lost acknowledgement, duplicate request, delayed completion, and controller restart. If either side cannot reconcile ownership, enter a visible uncertain state and invoke the defined model recovery. Do not invent a new identifier automatically for the same physical carrier just to escape the timeout.

Bring this design to the professional review, where the goal is to challenge assumptions before a machine does.

Now make the decision yourself

Use the chapter’s model on a fresh question, then compare your reasoning with the worked decision.

How this becomes a program

Two controllers believe they own the same carton. Which transition went wrong?

The source released work while the destination recorded arrival, but neither side has a durable agreement about the transaction.

PLCPLCSource ownerTransfer IDDestination ownerrequest → evidence → acknowledgement

Your first artifact

Write the invariant ‘each carton has exactly one recorded owner’. Then define the acknowledgement boundary and recovery dialogue across a lost link.

Open the worked decision
TransferComplete := ArrivalConfirmed
                    AND MatchingAckReceived;

Why this line belongs here

Completion is a transaction result. The chapter's protocol records identity and reservations so a delayed message cannot silently complete a different transfer. Physical location and logical ownership both need reconciliation.

Change the task

Only station B restarts after power loss. Describe the first exchange that prevents either station from inventing a new carton transaction.