PPT

Programming Language Semantics
Axiomatic Semantics of
Parallel Programs
Tentative Schedule
• 15/6 Parallel Programs
• 22/6 Rely/Guarantee Reasoning
– Assignment 2
• 29/6 Separation Logic
• 6, 3/7 Type Inference
– Assignment 3
Plan
• More on Hoare Proof Rules
• Proof Rules for Concurrent Programs
Hoare Proof Rules for Partial Correctness
{A} skip {A}
{B[a/X]} X:=a {B} (Assignment Rule)
{P} c0 {C} {C} c1 {Q}
(Composition Rule)
{P} c0;c1{Q}
{Pb} c0 {Q} {P b} c1 {Q}
(Conditional Rule)
{P} if b then c0 else c1{Q}
{Ib} c {I}
(Loop Rule)
{I} while b do c{Ib}
P  P’ {P’} c {Q’}  Q’  Q
{P} c {Q}
(Consequence Rule)
Potential Language Extensions
• Blocks
• Procedures
– Procedures as parameters
•
•
•
•
Abstract data types
Non-determinism
Parallelism
Arrays, Pointers, and Dynamic allocations
More Rules
{P1} c {Q1} {P2} c {Q2}
{P1 P2} c {Q1 Q2}
{P} c {P} where Mod(c)Var(P) = 
(Conjunction Rule)
(Invariance Rule)
Underlying Principles of
Hoare Rules
• Commands are predicate transformers
• Different behaviors for different
preconditions
• Commands can be partial
– Resource restriction
– Implementation restriction
• In {P} comm {Q}
– P and Q are contracts with the clients of comm
An Axiomatic Proof Technique
for Parallel Programs
Owicky & Gries
Verification of Sequential and Concurrent Programs
Apt & Oldrog
Chapters 4-6
IMP+ Parallel Constructs
• Abstract syntax
com::= X := a | skip | com1 ; com2 |
if b then com1 else com2 |
while b do com|
cobegin com1 || com2 … || comk coend
• All the interleavings of are executed
• Example
– cobegin X := 1 || (X :=2 ; X := X+2) coend
A First Attempt
{P1} c1 {Q1} {P2} c2 {Q2}.. {Pk} ck {Qk}
(Parallel Rule)
{P1 P2 … Pk} cobegin c1 || c2 || …|| cn coend {Q1 Q2 …  Qk}
Simple Examples
{true} X := 1 { X >0 } {true} Y:= 1 {Y>0}
{true} cobegin X :=1 || Y := 1 coend{X>0 Y >0}
{true} X := 1 { X >0 } {true} X:=2 ; X := X+2 {X>0}
{true} cobegin X :=1 || X:=2 ; X := X+2 coend{X>0 }
Unsoundness
{Y=1} X := 0 { Y=1 } {true} Y:=0 {true}
{Y=1} cobegin X :=0 || Y:=0 coend {Y=1 }
Modified Parallel Rule
{P1} c1 {Q1} {P2} c2 {Q2}.. {Pk} ck {Qk}
{P1 P2 … Pk} cobegin c1 || c2 || …|| ck coend {Q1 Q2 …  Qk}
Mod(cj)Var(Pi) = 
Mod(cj)Var(Qi) = 
ij
Unsoundness from sharing
{true} X := 1 { X >0 } {true} X:=2 ; X := X+2 {X>3}
{true} cobegin X :=1 || X:=2 ; X := X+2 coend {X>3 }
Handling Shared Variables
• Carefully design the proofs of every thread
to make them local
• Show that the code of other threads do not
interfere with the proofs of other threads
Interference
• A command T with a precondition pre(T) does not
interfere with the proof of {P} C {Q} if:
– {Q  pre(T) } T {Q}
– For any command C’ inside C with a precondition
pre(C’)
• {pre(C’)  pre(T) } T {pre(C’)}
• {P1} c1 {Q1} {P2} c2 {Q2}.. {Pk} ck {Qk} are
interference free if for every i j and for every
assignment in T in ci does not interfere with
{Pj} cj {Qj}
Modified Parallel Rule
{P1} c1 {Q1} {P2} c2 {Q2}.. {Pk} ck {Qk}
{P1 P2 … Pk} cobegin c1 || c2 || …|| ck coend {Q1 Q2 …  Qk}
{P1} c1 {Q1} {P2} c2 {Q2}.. {Pk} ck {Qk} are
interference free
No unsoundness from sharing
{true} X := 1 { X >0 } {true} X:=2 ; X := X+2 {X>3}
{true} cobegin X :=1 || X:=2 ; X := X+2 coend {X>3 }
A Realistic Example
ES=eventopM+1
Findpos: begin
initialize: i :=2 ; j :=1; eventop = M+1 ; oddtop := M+1;  even(i)
 l: (even(l)  0<l<i) x(l)0
search: cobegin
Evensearch: while i < min(oddtop, eventop) do
 eventopM x(eventop)>0
if (x(i) > 0) then eventop := i
else i := i + 2;
OS=oddtopM+1
||
 odd(j)
Oddsearch: while j < min(oddtop, eventop) do
 l: (odd(l)  0<l<j) x(l)0
if (x(j) > 0) then oddtop := j
else j := j + 2;
 oddtopM x(oddtop)>0
coend
k := min(eventop, oddtop)
end {k M+1 (l: 1 l <k  x(l) 0)  (k M x(k)>0)}
Incompleteness
• There exist correct programs which cannot
be verified by the parallelization rule
– {X = Y} cobegin X := X + 1 || Y := Y+1 coend {X=Y}
An Informal Proof of
{X = Y} cobegin X := X + 1 || Y := Y+1 coend {X=Y}
{X = Z} X : = X + 1 { X = Z +1}
{Y = Z} Y : = Y + 1 { Y = Z +1}
{X = Z  Y = Z} cobegin X := X + 1 || Y := Y+1 coend {X=Z+1  Y= Z+1}
{X = Z  Y = Z} cobegin X := X + 1 || Y := Y+1 coend {X=Y}
{X = Y} Z : = X { X = Y  Y = Z}
{X =Y }
Z : = X ; cobegin X := X + 1 || Y := Y+1 coend {X=Y}
{X =Y }
cobegin X := X + 1 || Y := Y+1 coend {X=Y}
Auxiliary Variables
• Record history information
• A set of variables AV is auxiliary for a command S if each
variable from AV only occurs in assignments of the form X
:= t where X  AV
• Auxiliary variable elimination rule
{P} S {Q}
{P} S’ {Q}
Where A is auxiliary for S
FV(Q) A = 
FV(P) A = 
S’ results from S by deleting all assignments in to variables in S
A Formal Proof of
{X = Y} cobegin X := X + 1 || Y := Y+1 coend {X=Y}
{X = Z} X : = X + 1 { X = Z +1}
(Assign-Rule)
{Y = Z} Y : = Y + 1 { Y = Z +1}
(Assign-Rule)
{X = Z  Y = Z} cobegin X := X + 1 || Y := Y+1 coend {X=Z+1  Y= Z+1}
(Par-Rule)
{X = Z  Y = Z} cobegin X := X + 1 || Y := Y+1 coend {X=Y}
{X = Y} Z : = X { X = Y  Y = Z}
{X =Y }
(Cons.-Rule)
(Assign-Rule)
Z : = X ; cobegin X := X + 1 || Y := Y+1 coend {X=Y}
(Comp.-Rule)
{X =Y }
cobegin X := X + 1 || Y := Y+1 coend {X=Y}
(Aux.-Rule)
Synchronization Primitives
• Support for atomic sections and communication
• A High Level Construct
await B then S
– No parallelization in S
– Blocked until B holds
– If B is true then S is executed atomically
• Examples
– await true then S
– Await “some condition” then skip
– Semaphore
• P(sem): await sem >0 then sem := sem – 1
• V(sem): await true then sem := sem + 1
Interference (modified)
• A command T with a precondition pre(T) does not
interfere with the proof of {P} C {Q} if:
– {Q  pre(T) } T {Q}
– For any command C’ inside C but not within await with
a precondition pre(C’)
• {pre(C’)  pre(T) } T {pre(C’)}
• {P1} c1 {Q1} {P2} c2 {Q2}.. {Pk} ck {Qk} are
interference free if for every i j and for every
assignment not inside await or an await T in ci
does not interfere with
{Pj} cj {Qj}
An Inference Rule for Await
{P b} c {Q}
{P } await B then c {Q}
Producer-Consumer
•
•
•
•
•
•
•
Two processes communicating via a shared bounded buffer
Consumer waits for the buffer to be filled
Producer waits for the buffer to be non-full and fills the buffer
buffer[0..N-1]
in – the number of elements added
out – the number of elements deleted
buffer[out mod N], … buffer[(out + in – out -1) mod N] elements
Producer/Consumer Code
in := 0; out := 0 ;
cobegin
producer: …
await in-out < N then skip
add: buffer(in mod N) := next value;
markin: in := in +1;
…
||
consumer: …
await in-out >0 then skip
remove: this value := buffer(out mod N);
markout: out := out +1;
…
coend
in := 0; out := 0 ; i := 1; j :=1;
{M 0}
cobegin
producer: while i M do
begin x:= A[i];
I= k: out < k M  buffer[(k-1} mod N] = A[k]
 0 in-out N
await in-out <N then skip;
 0 i M+1
add: buffer[in mod N] := x ;
 0 j M+1
markin: in := in + 1;
i := i + 1
end
||
consumer: while j M do
begin await in-out >0 then skip;
remove: y := buffer[out mod N] ;
markout: out := out + 1;
B[j] := y;
j := j + 1
end
coend {k: 1 k M  B[k] = A[k]}
{I i = in+1=1 j=out+1=1}
cobegin
{I  i = in+1=1}
producer: while i M do
begin x:= A[i];
I= k: out < k M  buffer[(k-1} mod N] = A[k]
 0 in-out N
await in-out <N then skip;
 0 i M+1
add: buffer[in mod N] := x ;
 0 j M+1
markin: in := in + 1;
i := i + 1
end {I  i = in+1=M+1}
|| {I  j = out+1=1}
consumer: while j M do
begin await in-out >0 then skip;
remove: y := buffer[out mod N] ;
markout: out := out + 1;
B[j] := y;
j := j + 1
end {I  k: 1 k M  B[k] = A[k]}}
coend {k: 1 k M  B[k] = A[k]}
Summary
• Reasoning about concurrent programs is difficult
• Aweeki-Gries suggest to carefully design the
sequential proofs to simplify the proof procedure
• The use of auxiliary variables can make proofs
difficult
• Can have difficulties with fine-grained
concurrency
– Benign dataraces
• Rely/Guarantee style can allow more
elegant/general reasoning (next lesson)