Directed Algebraic Topology and Concurrency: Introduction

Teacher: Emmanuel Haucourt

One of the first models:

  • process algebras (most famous forms: CCS and CSP):

    • syntactic model
    • build programs by means of parallel composition:

      • || (parallel execution, commutative)
      • ; (sequential, obv. not commutative)
      • + (non deterministic choice, commutative)
  • Petri Nets
  • Event structures
  • etc…

⟶ in the Handbook of Logic and Computer Science (Abramsky, …): comparison of different models (adjunctions between them, etc…)

In practical programming: the only data structure really well understood from a concurrency point of vue are the linked lists

Dijkstra: wrote the paper « Cooperating squential processes » to explain how to implement a synchronisation system in any imperative programming language (add an extra layer to execute processes in parallel): semaphores, etc…

Parallel Automata Meta-Language (PAML)

Start with a program $P$ ⟶ compute its control flow graph (turns the orginal source code into an automaton)

This construction is very well-known from sequential program, but not for parallel program.

Question: What is the concurrent couterpart to control flow graphs?

In the first part of the course: we will generalize what was done in the seminal paper « The Geometry of Semaphore Programs, S. D. Carson and P. F. Reynolds, 1987 »

What did Dijkstra: designed an extension of ALGOL (algorithm language) where you can

  • P (lock/take)
  • V (unlock/release)
  • parbegin ... parend: sequences in parallel
  • the memory is shared (concurrent read, but exclusive write (no two programs can write at the same time))

POSIX threads: if you’re able to analyse any program made with POSIX threads, you can analyse any Unix operating system ⟶ not doable nowadays

Parallel composition can happen anywhere in the program:

x:=0 ; y:=0 ; (x:=1 || y:=1)

Carson and Reynolds version: restriction of Dijkstra’s language, because

  • || must appear in outermost position:

      P_1 ||  || P_n
    

    where P_i is sequential

  • no branching and no loops


In the model we will consider:

  • synchronisation barriers W (wait) are allowed. E.g.:

      W(b) || W(b) || W(b)
    

    barrier with “arity” 3

  • no pointer arithmetics/no function call (only jumps)/no birth and death of processes at runtime: you want to provide a model at compile time

  • When a process own a resource, it is the only one to be able to release it

  • Conservative processes:

    • in physics, a force field is conservative if the amount energy doesn’t depend on the path, only on the end points
    • similarly for processes: if you can compute the amount of resources needed based on the position of the instruction pointer in the control flow graph ⟶ conservative

Declarations:

  • Semaphores: sem, used with P and V
  • Synchronisation barrier: sync, with W
  • Mutexes mtx, Variables var, Processes proc, and initialisation init

Instructions:

  • identifier:=expression
  • P(identifier) takes an occurrence of the resource identifier if it’s available
  • V(identifier): dual operation, releases an occurence of the resource identifier
  • W(identifier): barrier identifier
  • J(identifier): jump at identifier

Ex: Syracuse algorithm:

proc p = x:=7;J(q)
proc q = J(r)+[x<>1]+()
proc r = (x:=x/2)+[x%2=0]+(x:=3*x+1) ; J(q)
init p

Control flow graphs

Invented independently by Allen (for compilers) and Floyd (for static analysis)

Control flow graph:

a finite mathematical object which represents all the possible execution traces

On the edges do matter when you have concurrent programs, because things may happen there.

Execution trace ⟹ a path in the control flow graph

BUT: the converse is not true. But actually, the control flow graph is in a way the “best” finite aproximation of all the execution traces (you can’t have a finite representation of exactly all the execution traces, because of indecidability)

Abstract machine: mathematical object that “reacts” to all the instructions. Instructions act on the set of states.

Set of variables: $𝒳$

Valuation/memory state:

\[ν: 𝒳 ⟶ ℝ_⊥ ≝ ℝ ∪ \lbrace ⊥ \rbrace\]

Expression:

\[ε: \lbrace \text{valuations}\rbrace ⟶ ℝ\\ \text{Free variables: } ℱ(ε)\]

Set of expressions occurring in the program: $ℰ$

Interpretation of expressions:

\[⟦x⟧_ν \; ≝ \; ν(x) \quad ∀ x ∈ 𝒳\\ \text{and then, inductively defined}\]

(cf picture)

Parallel execution ⟺ Tensor product in the category of pre-cubical sets

State $σ$:

  • $σ(x) ∈ ℝ_⊥$
  • $σ(s): \lbrace 1, …, n\rbrace ⟶ ℕ ∪ \lbrace ∞\rbrace$

    • $σ(s)(i)$: the number of occurrences of $s$ held by the $i$-th process

Leave a comment