Bas van den Heuvel
2024-05-17
Given threads and event in thread , the vector clock of is denoted where is the last-known timestamp of thread . Hence, !
Given two vector clocks , we say if Hence, if is aware of the “latest information” of on all threads, but has later information on at least one thread!
Given an event in thread . The vector clock depends on other events:
Hence:
Recall event sets. Given events with event sets , respectively, we consider if .
We can prove that if and only if . Hence, if !
Given an event , the lockset of is the set of locks that is a critical section of: the acquire and release events surround in the same thread.
Two events are “concurrent” if their locksets do not overlap.
T1 T2
e1. fork(T2)
e2. wr(x)
e3. rd(x)
e4. rd(x)
e5. wr(x)
T1 T2 VC
e1. fork(T2) [1,0]
e2. wr(x) [2,0]
e3. rd(x) [3,0]
e4. rd(x) [1,1]
e5. wr(x) [1,2]
Data race; for example, and are incomparable ( and and ).
T1 T2 FT
e1. fork(T2) Th(2)=[1,1]
Th(1)=[2,0]
e2. wr(x) W(x)=1#2
Th(1)=[3,0]
e3. rd(x) R(x)=[3,0]
Th(1)=[4,0]
e4. rd(x) j#k=W(x)=1#2
k>Th(2)(j)=2>1
read-write
R(x)=[3,1]
Th(2)=[1,2]
e5. wr(x) not R(x)<Th(2)
write-read
T1 T2 LS
e1. fork(T2) {}
e2. wr(x) {}
e3. rd(x) {}
e4. rd(x) {}
e5. wr(x) {}
None of the locksets overlap, so all conflicting events are in a data
race (false positive when last-writer violated).
T1 T2
e1. fork(T2)
e2. wr(x)
e3. wr(y)
e4. rd(y)
e5. wr(x)
T1 T2 VC
e1. fork(T2) [1,0]
e2. wr(x) [2,0]
e3. wr(y) [3,0]
e4. rd(y) [1,1]
e5. wr(x) [1,2]
and are incomparable, but false positive: last-writer violated!
T1 T2 FT
e1. fork(T2) Th(2)=[1,1]
Th(1)=[2,0]
e2. wr(x) W(x)=1#2
Th(1)=[3,0]
e3. wr(y) W(y)=1#3
Th(1)=[4,0]
e4. rd(y) j#k=W(y)=1#3
k>Th(2)(j)=3>1
read-write
R(y)=[1,1]
Th(2)=[1,2]
e5. wr(x) j#k=W(x)=1#2
k>Th(2)(j)=2>1
write-write
T1 T2
e1. fork(T2)
e2. wr(a)
e3. acq(x)
e4. wr(b)
e5. rel(x)
e6. wr(c)
e7. acq(x)
e8. rd(a)
e9. rd(b)
e10. rel(x)
e11. wr(c)
T1 T2 VC
e1. fork(T2) [1,0]
e2. wr(a) [2,0]
e3. acq(x) [3,0]
e4. wr(b) [4,0]
e5. rel(x) [5,0]
e6. wr(c) [6,0]
e7. acq(x) [5,1]
e8. rd(a) [5,2]
e9. rd(b) [5,3]
e10. rel(x) [5,4]
e11. wr(c) [5,5]
All vector clocks are ordered, except and : data race (true positive).
T1 T2 FT
e1. fork(T2) Th(2)=[1,1]
Th(1)=[2,0]
e2. wr(a) W(a)=1#2
Th(1)=[3,0]
e3. acq(x) Th(1)=[4,0]
e4. wr(b) W(b)=1#4
Th(1)=[5,0]
e5. rel(x) Rel(x)=[5,0]
Th(1)=[6,0]
e6. wr(c) W(c)=1#6
Th(1)=[7,0]
e7. acq(x) Th(2)=[5,1]
Th(2)=[5,2]
e8. rd(a) j#k=W(a)=1#2
not k>Th(2)(j)=2>5
R(a)=[5,2]
Th(2)=[5,3]
e9. rd(b) j#k=W(b)=1#4
not k>Th(2)(j)=4>5
R(b)=[5,3]
Th(2)=[5,4]
e10. rel(x) Rel(x)=[5,4]
Th(2)=[5,5]
e11. wr(c) j#k=W(c)=1#6
k>Th(2)(j)=6>5
write-write
T1 T2 LS
ls(1)={}
ls(2)={}
e1. fork(T2)
e2. wr(a) LS(e2)=ls(1)={}
e3. acq(x) ls(1)=ls(1)+{x}={x}
e4. wr(b) LS(e4)=ls(1)={x}
e5. rel(x) ls(1)=ls(1)-{y}={}
e6. wr(c) LS(e6)=ls(1)={}
e7. acq(x) ls(2)=ls(2)+{x}={x}
e8. rd(a) LS(e8)=ls(2)={x}
e9. rd(b) LS(e8)=ls(2)={x}
e10. rel(x) ls(2)=ls(2)-{x}={}
e11. wr(c) LS(e11)=ls(2)={}
Non-overlapping locksets: data races (all true positives).
T1 T2
e1. fork(T2)
e2. acq(x)
e3. wr(a)
e4. rel(x)
e5. acq(x)
e6. rd(a)
e7. rel(x)
T1 T2 VC
e1. fork(T2) [1,0]
e2. acq(x) [2,0]
e3. wr(a) [3,0]
e4. rel(x) [4,0]
e5. acq(x) [4,1]
e6. rd(a) [4,2]
e7. rel(x) [4,3]
All vector clocks are ordered: no data race (true negative).
T1 T2 FT
e1. fork(T2) Th(2)=[1,1]
Th(1)=[2,0]
e2. acq(x) Th(1)=[3,0]
e3. wr(a) W(a)=1#3
Th(1)=[4,0]
e4. rel(x) Rel(x)=[4,0]
Th(1)=[5,0]
e5. acq(x) Th(2)=[4,1]
Th(2)=[4,2]
e6. rd(a) j#k=W(a)=1#3
not k>Th(2)(j)=3>4
R(a)=[4,2]
Th(2)=[4,3]
e7. rel(x) Rel(x)=[4,3]
Th(2)=[4,4]
T1 T2 LS
ls(1)={}
ls(2)={}
e1. fork(T2)
e2. acq(x) ls(1)={x}
e3. wr(a) LS(e3)={x}
e4. rel(x) ls(1)={}
e5. acq(x) ls(2)={x}
e6. rd(a) LS(e6)={x}
e7. rel(x) ls(2)={}
All locksets overlap: no data race (true negative).
T1 T2
e1. fork(T2)
e2. acq(l)
e3. wr(x)
e4. rel(l)
e5. acq(l)
e6. wr(x)
e7. rel(l)
e8. rd(x)
T1 T2 VC
e1. fork(T2) [1,0]
e2. acq(l) [2,0]
e3. wr(x) [3,0]
e4. rel(l) [4,0]
e5. acq(l) [4,1]
e6. wr(x) [4,2]
e7. rel(l) [4,3]
e8. rd(x) [4,4]
All vector clocks are ordered: no data race (false negative).
T1 T2 FT
e1. fork(T2) Th(2)=[1,1]
Th(1)=[2,0]
e2. acq(l) Th(1)=[3,0]
e3. wr(x) W(x)=1#3
Th(1)=[4,0]
e4. rel(l) Rel(l)=[4,0]
Th(1)=[5,0]
e5. acq(l) Th(2)=[4,1]
Th(2)=[4,2]
e6. wr(x) j#k=W(x)=1#3
not k>Th(2)(j)=3>4
W(x)=2#2
Th(2)=[4,3]
e7. rel(l) Rel(l)=[4,3]
Th(2)=[4,4]
e8. rd(x) j#k=W(x)=2#2
not k>Th(2)(j)=2>4
T1 T2 LS
ls(1)={}
ls(2)={}
e1. fork(T2)
e2. acq(l) ls(1)={l}
e3. wr(x) LS(e3)={l}
e4. rel(l) ls(1)={}
e5. acq(l) ls(2)={l}
e6. wr(x) LS(e6)={l}
e7. rel(l) ls(2)={}
e8. rd(x) LS(e8)={}
Non-overlapping locksets: data race (true positive).
T1 T2 T3
e1. fork(T3)
e2. acq(l)
e3. fork(T2)
e4. wr(x)
e5. join(T2)
e6. rel(l)
e7. acq(l)
e8. wr(x)
e9. rel(l)
e10. rd(x)
T1 T2 T3 VC
e1. fork(T3) [1,0,0]
e2. acq(l) [2,0,0]
e3. fork(T2) [3,0,0]
e4. wr(x) [3,1,0]
e5. join(T2) [4,1,0]
e6. rel(l) [5,1,0]
e7. acq(l) [5,1,1]
e8. wr(x) [5,1,2]
e9. rel(l) [5,1,3]
e10. rd(x) [5,1,4]
All vector clocks are ordered: no data race (false negative).
T1 T2 T3 FT
e1. fork(T3) Th(3)=[1,0,1]
Th(1)=[2,0,0]
e2. acq(l) Th(1)=[3,0,0]
e3. fork(T2) Th(2)=[3,1,0]
Th(1)=[4,0,0]
e4. wr(x) W(x)=2#1
Th(2)=[3,2,0]
e5. join(T2) Th(1)=[4,2,0]
Th(1)=[5,2,0]
e6. rel(l) Rel(l)=[5,2,0]
Th(1)=[6,2,0]
e7. acq(l) Th(3)=[5,2,1]
Th(3)=[5,2,2]
e8. wr(x) j#k=W(x)=2#1
not k>Th(3)(j)=1>5
W(x)=3#2
Th(3)=[5,2,3]
e9. rel(l) Rel(l)=[5,2,3]
Th(3)=[5,2,4]
e10. rd(x) j#k=W(x)=3#2
not k>Th(3)(j)=2>4
T1 T2 T3 LS
ls(1)={}
ls(2)={}
ls(3)={}
e1. fork(T3)
e2. acq(l) ls(1)={l}
e3. fork(T2)
e4. wr(x) LS(e4)={}
e5. join(T2)
e6. rel(l) ls(1)={}
e7. acq(l) ls(3)={l}
e8. wr(x) LS(e8)={l}
e9. rel(l) ls(3)={}
e10. rd(x) LS(e10)={}
Non-overlapping locksets: data race (both false and true positive).