CEG 7370: Distributed Computing Principles

Mathematics of Shared Variables

Prabhaker Mateti

This page is about shared variable concurrency issues, using mathematical logic. It assumes you read through the notes on assertions.

Fine Grained Atomicity

S1 :: x := y
S2 :: y := z
S0 :: co S1 || S2 oc
  Final value of x can be:
old-y or z

  
S1:: y := 0; z := 0
S2:: x := y + z
S3:: y := 1; z := 2
S0:: S1; co S2 || S3 oc
  Final value of x can be:
0, 1, 2, or 3

  
co x := y + y || y := 1 oc  

has two references to y. y + y can read both the old and new values of y in either instance.


  
||  Interpret as (e.g. Java) threads

Specifying Synchronization

  1. The await statement ‹ await B → S › is a coarse grained construct.
  2. Condition synchronization: ‹ await B ›
  3. Unconditional atomic action: ‹ S ›
  4. Conditional atomic action: ‹ await B → S ›
  5. Is ‹ await B › implemented as do not B → skip od correct?

  6. Await Rule: {P & B} S {Q} ⇒ {P} ‹ await B → S › {Q}

At-Most-Once(e)

  1. for-all x in sharedVars(e): (nrefs(x, e) ≤ 1)

    1. Simple variable ≡ a whole variable, not a "part", e.g., array[i];
    2. e is an expression of "this" process; P stands for any "other" process
    3. writeVars(P) ::= vars P modifies; readVars(P) ::= vars P reads
    4. sharedVars(e) ::= modified by others
    5. nrefs(x, e) ::= (free) occurs of x in e
  2. ‹ await B › implemented as do not B → skip od is correct if At-Most-Once(B)

At-Most-Once(x := e)

  1. (At-Most-Once(e) & x not-in readVars(P))   OR
    (simpleVar(x) & refVars(e) disjoint-with writeVars(P))

    1. writeVars(P) ::= vars P modifies, readVars(P) ::= vars P reads
    2. refVars(P) ::= vars P reads/writes
  2. A statement using shared variables obeying the At-Most-Once property executes as if it were atomic.

Deduction Rules

  1. {x = 0 & y = 0} co x := x + 1 || y := y + 1 oc {??}
    x = 1? y = 1? Yes.
  2. Can we generalize this? Suppose {Pi} Si {Qi}. Can we then conclude
    {P1 & P2 & ... & Pn} co S1 || S2 || ... || Sn oc {Q1 & Q2 &...& Qn} ?
  3. No.    E.g.,    Si :: x := x + 1,   Pi ≡ {x = 0}, Qi ≡ {x = 1}

  4. We have interference.

Interference, Intuitively speaking ...

  1. A program consisting of several processes (threads) works "well" zillions of times, but every once in a while it works incorrectly. Problem could be shared variable interference.
  2. Consider the execution of statement Si of a chosen process. There must be a precondition for Si (whether you bothered to write it or not). Consider the weakest such precondition Pi. In all the zillions of times, this Pi was True, and Si works "well".
  3. Suppose Pi became False because of other processes. Rarely, ofcourse. Si no longer works "well". This is not going to be solved by inserting Si into ‹ Si ›
  4. Is this going to happen with all Si? Only for certain "important" ones.

Free of Interference

  1. We will identify critical assertions in the sense of "highly important".
  2. We verify that these are not becoming False due to other processes.

Critical Assertions

  1. Good coding: An assignment x := e executes atomically:
    1. At-Most-Once(x := e)
    2. ‹ x := e ›
  2. Complete proof oultine: An assertion before and after each statement.
  3. {P(e)} ‹ x := e › {P(x)} P(e) is a critical assertion.

  4. {P} ‹ S1; {Q} S2 › {R} Q is not a critical assertion. The state of the process after S1 is not visible to others.
  5. Consider the complete proof of {P} S {Q}. S contains || and ‹ ›

    1. Q is a critical assertions, and
    2. for each statement T within S that is not within an await statement,
      {pre(T)} T {post(T)}, the weakest predicate pre(T) is a critical assertions.

Non-Interference

  1. Assignment action A. Critical assertion C.

  2. A does not interfere with C, NI(A, C), if {C & pre(A)} A {C}.

Interference Freedom

{Pi} Si {Qi}, 1 ≤ i ≤ n,
are interference-free if
     for-all A in Si
         for-all C in Sj, i ≠ j,
             NI(A, C) holds.
  

Concurrency Rule

{Pi} Si {Qi}, 1 ≤ i ≤ n, are interference-free

{P1 & ... & Pn}
co S1 || S2 || ... || Sn oc
{Q1 & ... & Qn}

Avoiding Interference

  1. #histories of a conc program is exponential in #atomic-actions
  2. #ways of interferences is much smaller
  3. Disjoint Variables: (writeVars(P1) disjoint refVars(P2) & writeVars(P2) disjoint refVars(P1)) implies P1 and P2 do not interfere.

Weakened Assertions-1

Concurrency Rule is sufficient, but not necessary. E.g., we can intuitively see that x = 3 after S0 in the following.

X0:: x := 0

S1:: ‹ x := x + 1 ›
S2:: ‹ x := x + 2 ›

S0:: X0; co S1 || S2 oc
 

Clearly, post S0 we have x = 3. But, with
{x = 0} S1 { x = 1}
{x = 0} S2 { x = 2}
valid (in isolation), that x = 3 cannot be proven.

S1 interferes with x = 0, and x = 2.
S2 interferes with x = 0, and x = 1.

Weakened Assertions-2

X0:: x := 0

S1:: ‹ x := x + 1 ›
S2:: ‹ x := x + 2 ›

S0:: X0; co S1 || S2 oc
 

We can show, using the rules we have so far,

{(x = 0 or x = 1) & (x = 0 or x = 2)}
co S1 || S2 oc
{(x = 2 or x = 3) & (x = 1 or x = 3)}

Pre- simplifies to x = 0. Post- simplifies to x = 3.

  1. Even when writeVars(P) overlap refVars(P), there may not be interference.
  2. The "Weekened Assertion" method is for this situation.
    About shared variables, make a weaker assertion than could be made if processes were executed in isolation.

Weakened Assertions-3

weaken {x = 0} S1 { x = 1} to    {x = 0 or x = 2} S1 { x = 1 or x = 3}
weaken {x = 0} S2 { x = 2} to    {x = 0 or x = 1} S2 { x = 2 or x = 3}

Claim: S1 does not interfere with pre(S2).
Proof: Show NI(S1, pre(S2)) holds.

  1. i.e., show {pre(S2) & pre(S1)} S1 {pre(S2)}.
  2. i.e., show {(x = 0 or x = 1) & (x = 0 or x = 2)} S1 {(x = 0 or x = 1)} holds.
  3. i.e., show {x = 0} S1 {(x = 0 or x = 1)} holds.
  4. i.e., show (x = 0) ⇒ (x+1 = 0 or x+1 = 1) holds.
  5. i.e., show (x = 0) ⇒ (x = -1 or x = 0) holds. QED

Weakened Assertions-4

Claim: S2 does not interfere with pre(S1).
Proof: similar

Now, we can instantiate the Concurrency Rule
{x = 0 or x = 2} S1 { x = 1 or x = 3}
{x = 0 or x = 1} S2 { x = 2 or x = 3}
no interference

{(x = 0 or x = 2) & (x = 0 or x = 1)} co S1 || S2 oc {(x = 1 or x = 3) & (x = 2 or x = 3)}

The above simplifies to {x = 0} co S1 || S2 oc {x = 3}

Global Invariants

  1. An assertion I is a global invariant if it is true (i) before the processes begin, and (ii) before and after every assignment action of all processes.
  2. {I & pre(a)} a {I}, for all a taken from all processes.
  3. C ≡ I & L, where C is a critical assertion of Pj and L an assertion about private/local variables of Pj.
  4. If all assertions are of the above form, the processes are interference-free.
  5. Study the proof of the Array Copy from Andrews book.

Synchronization

  1. co P1:: ... {pre(a)} a ...
    ||   P2:: ... S1; {C} S2 ...
    oc

    Suppose a interferes with critical assertion C.
  2. Solution-1: Hide C from a, using mutex in P2: ‹ S1; S2 ›
  3. Solution-2: Replace a of P1 with ‹ await not C or wp(a, C) → a ›

Auxiliary Variables-1

  1. Program counters of different processes
  2. Introduce aux vars solely for proof purposes.
  3. Suppose S' has aux variables. S is S1 with all statements using aux vars deleted. Suppose P, Q are assertions about regular vars. Then,

    {P} S' {Q} ⇒ {P} S {Q}

Auxiliary Variables-2

var x := 0; var t1 := 0; var t2 := 0; {Let I ≡ x = t1 + t2}
{I & t1 = 0 & t2 = 0}
co {I & t1 = 0} ‹ x := x+1; t1 := 1 › {I & t1 = 1}
||   {I & t2 = 0} ‹ x := x+1; t2 := 1 › {I & t2 = 1}
oc
{I & t1 = 1 & t2 = 1}

Each assertion is an & of a global invariant and an assertion on vars not used by the other process. The above is interference-free. Thus, the above is a valid conclusion.

Proving Safety Properties

  1. See temporal logic for defs of safety and liveness.
  2. To prove that an assertion F is a safety property of a program G, show that
    every C ⇒ F, where C are critical assertions from {P} G {Q}
  3. Our phrasing above differs from Andrews for th ebetter.
  4. Exclusion of Configs. Suppose P & Q is false. A process cannot then be in a state satifying P when/while another process is in a state statisfying Q.

Liveness and Fairness

  1. Most liveness properties depend on fairness. See fairness-etc.
  2. See temporal logic for defs of weak and strong fairness.

Exercises

  1. See the Exercises in Andrews, Chapters 1 and 2.
  2. Does the precondition and statement {x  ≥ 4 } ‹ x := x - 4 › interfere with the triple {x is odd} ‹ x := x + 5 › {x is even}.
  3. Using the technique of weakened assertions, prove that {x = 1} S {x = 7} is a theorem, where S is co ‹ x := x+1› || ‹ x := x+2› || ‹ x := x+3› oc

References

  1. Gregory R. Andrews, Concurrent Programming: Principles and Practice, Benjamin/Cummings, 1991. Chapters 1 and 2: Required Reading.
  2. Mark Batty, Scott Owens, Susmit Sarkar, Peter Sewell, and Tjark Weber, Mathematizing C++ Concurrency, ACM POPL 2011. Web-search for its pdf. Recommended Reading.

Copyright © 2014 pmateti@wright.edu