ZetCode

Algol 68 parallel clause

last modified November 13, 2026

A parallel clause runs the units of a collateral clause at the same time. PAR (unit, unit) is the syntax, and the units share the variables of the block that contains them. SEMA, LEVEL, DOWN, and UP coordinate their access to those variables.

This article describes the clause, the semaphores, and the discipline that a program needs when two units touch the same variable. The last section explains what this particular implementation does with the clause, which is why the examples are written the way they are.

Two units

Each comma-separated part of a PAR clause is a unit, and the clause yields VOID. The units may assign to variables declared before the clause, and the values are complete when the clause ends, so the results are printed afterwards.

units.a68
BEGIN
  INT a, b;
  PAR (
    a := 2 + 2,
    b := 3 * 3
  );
  print(("a = ", whole(a, 0), ", b = ", whole(b, 0), newline))
END

The two assignments are independent, and the print reads both variables after the clause has finished. Printing after the clause also keeps the output in one piece, which matters when the units really do run at the same time.

$ a68g units.a68
a = 4, b = 9

Collecting results in a row

A row is a natural place for the results of parallel work: every unit writes its own element, and no two units write the same place. The fourth unit reads a variable declared before the clause, which is allowed because reading a value that nobody writes is safe.

row.a68
BEGIN
  INT n := 5;
  [1:4] INT results;
  PAR (
    results[1] := 1 * 1,
    results[2] := 2 * 2,
    results[3] := 3 * 3,
    results[4] := n * n
  );
  FOR i TO UPB results DO
    print((whole(results[i], 0), " "))
  OD;
  print((newline))
END

The four elements are printed in order after the clause, so the output does not depend on the order in which the units ran. A row of results is the usual shape of a program that splits a computation into independent parts.

$ a68g row.a68
1 4 9 25

A critical section

total +:= 1 is not a single action: the program reads the value, adds one, and stores it back. Two units that interleave those steps can both read the same value and one increment is lost. SEMA lock = LEVEL 1 creates a semaphore with one permit, and DOWN and UP mark the critical section.

mutex.a68
BEGIN
  SEMA lock = LEVEL 1;
  INT total := 0;
  PAR (
    FOR i TO 1000 DO DOWN lock; total +:= 1; UP lock OD,
    FOR i TO 1000 DO DOWN lock; total +:= 1; UP lock OD
  );
  print(("total ", whole(total, 0), newline))
END

Only one unit can be between DOWN and UP at a time, so the increments never overlap and the total is 2000 whatever the order of the units. Without the semaphore the result may be smaller, and the size of the loss changes from run to run. DOWN may only be used inside a parallel clause; elsewhere it raises a runtime error.

$ a68g mutex.a68
total 2000

Waiting for a signal

LEVEL 0 starts the semaphore with no permits, so DOWN waits until another unit calls UP. That is the shape of a handshake: one unit produces a value and signals, and the other waits for the signal and reads the value.

handshake.a68
BEGIN
  SEMA ready = LEVEL 0;
  INT value, got;
  PAR (
    (value := 42; UP ready),
    (DOWN ready; got := value)
  );
  print(("the consumer got ", whole(got, 0), newline))
END

The producer stores 42 and then signals; the consumer waits for the signal and copies the value. A unit that consists of several statements must be enclosed in parentheses, because the parts of a collateral clause are units and not serial clauses. The consumer cannot read the value before the producer has stored it, whichever unit starts first.

$ a68g handshake.a68
the consumer got 42

Counting the resources

LEVEL 2 gives the semaphore two permits, so two units may be inside the critical section at once and a third has to wait. This is the way a program limits the number of units that use a resource, such as a pool of connections or a fixed amount of memory.

slots.a68
BEGIN
  SEMA slots = LEVEL 2;
  INT used := 0;
  PAR (
    FOR i TO 3 DO DOWN slots; used +:= 1; UP slots OD,
    FOR i TO 3 DO DOWN slots; used +:= 1; UP slots OD
  );
  print(("used ", whole(used, 0), newline))
END

Six units pass through the section, three from each loop, and the count is 6. The permits do not change the total; they only decide how many units may be inside at one time, which is why the result is the same as with a mutex.

$ a68g slots.a68
used 6

What this build does

Algol 68 Genie accepts the parallel clause and the semaphores, and a program that uses them runs correctly. The implementation used for this article, version 2.8.4, executes the units of a clause one after another, however: two units that each call sleep(2) take four seconds in total, and two loops that print inside the units write their output one after the other instead of interleaving it.

That behaviour explains why the examples print their results after the clause and keep the printed text in one piece. A program written for a build with real threads must work for any interleaving, and the semaphores are the tool for that; a build that runs the units in sequence simply never makes a unit wait. The examples above are written so that both kinds of build produce the same output.

Next steps

The procedures article explains the PROC declarations that the units call, and references and the heap shows how a unit can share storage that outlives the clause. The loops article covers the FOR clauses inside the units, and environment and processes measures the time that a computation takes.

Source

Revised Report on the Algorithmic Language Algol 68

The Algol 68 Genie project

In this article we have run units in a parallel clause, collected their results in a row, protected a critical section with a semaphore of level 1, waited for a signal from a semaphore of level 0, limited the number of units inside a section with a semaphore of level 2, and seen how this build runs the units.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Algol 68 tutorials.