Art of Multiprocessor Programming

Concurrent Objects
Companion slides for
The Art of Multiprocessor
Programming
by Maurice Herlihy & Nir Shavit
Concurrent Computation
memory
object
object
Art of Multiprocessor
Programming
2
Objectivism
• What is a concurrent object?
– How do we describe one?
– How do we implement one?
– How do we tell if we’re right?
Art of Multiprocessor
Programming
3
FIFO Queue: Enqueue Method
q.enq( )
Art of Multiprocessor
Programming
4
FIFO Queue: Dequeue Method
q.deq()/
Art of Multiprocessor
Programming
5
A Lock-Based Queue
class LockBasedQueue<T> {
int head, tail;
T[] items;
Lock lock;
public LockBasedQueue(int capacity) {
head = 0; tail = 0;
lock = new ReentrantLock();
items = (T[]) new Object[capacity];
}
Art of Multiprocessor
Programming
6
A Lock-Based Queue
head
tail
0
1
y z 2
class LockBasedQueue<T> {
int head, tail;
T[] items;
Lock lock;
public LockBasedQueue(int capacity) {
head = 0; tail = 0;
lock = new ReentrantLock();
items = (T[]) new Object[capacity];
}
capacity-1
Queue fields
protected by
single shared lock
Art of Multiprocessor
Programming
7
A Lock-Based Queue
head
tail
0
1
y z 2
class LockBasedQueue<T> {
int head, tail;
T[] items;
Lock lock;
public LockBasedQueue(int capacity) {
head = 0; tail = 0;
lock = new ReentrantLock();
items = (T[]) new Object[capacity];
}
capacity-1
Initially head = tail
Art of Multiprocessor
Programming
8
Implementation: Deq
head
tail
0
public T deq() throws EmptyException
capacity-1 {
y z
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
Art of Multiprocessor
Programming
1
2
9
Implementation: Deq
head
tail
0
1
public T deq() throws EmptyException
capacity-1 {
y z 2
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
Method calls
lock.unlock();
mutually exclusive
}
}
Art of Multiprocessor
Programming
10
Implementation: Deq
head
tail
0
1
public T deq() throws EmptyException
capacity-1 {
y z 2
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
If queue empty
lock.unlock();
}
throw exception
}
Art of Multiprocessor
Programming
11
Implementation: Deq
head
tail
0
1
public T deq() throws EmptyException
capacity-1 {
y z 2
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
Queue not empty:
lock.unlock();
}
remove item and update
}
head
Art of Multiprocessor
Programming
12
Implementation: Deq
head
tail
0
1
public T deq() throws EmptyException
capacity-1 {
y z
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
Return result
lock.unlock();
}
}
Art of Multiprocessor
Programming
2
13
Implementation: Deq
head
tail
0
1
public T deq() throws EmptyException
capacity-1 {
y z 2
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
Release lock no
} finally {
matter what!
lock.unlock();
}
}
Art of Multiprocessor
Programming
14
Implementation: Deq
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
Art of Multiprocessor
Programming
15
Now consider the following
implementation
• The same thing without mutual exclusion
• For simplicity, only two threads
– One thread enq only
– The other deq only
Art of Multiprocessor
Programming
16
Wait-free 2-Thread Queue
public class WaitFreeQueue {
head
tail
0
capacity-1
int head = 0, tail = 0;
items = (T[]) new Object[capacity];
y z
1
2
public void enq(Item x) {
if (tail-head == capacity) throw
new FullException();
items[tail % capacity] = x; tail++;
}
public Item deq() {
if (tail == head) throw
new EmptyException();
Item item = items[head % capacity]; head++;
return item;
}}
Art of Multiprocessor
17
Programming
Wait-free 2-Thread Queue
head
head
public class WaitFreeQueue {
capacity-1
capacity-1
int head = 0, tail = 0;
items = (T[]) new Object[capacity];
0
0
tail
tail
1
yy zz
1
2
2
public void enq(Item x) {
if (tail-head == capacity) throw
new FullException();
items[tail % capacity] = x; tail++;
}
public Item deq() {
if (tail == head) throw
new EmptyException();
Item item = items[head % capacity]; head++;
return item;
}}
Art of Multiprocessor
18
Programming
Wait-free 2-Thread Queue
public class WaitFreeQueue {
head
tail
0
y z
int head = 0, tail = 0;
items = (T[]) new Object[capacity];
capacity-1
1
2
public void enq(Item x) {
if (tail-head == capacity) throw
new FullException();
items[tail % capacity] = x; tail++;
}
public Item deq() {
if (tail == head) throw
new EmptyException();
Queue
is item
updated
without a %
lock!
Item
= items[head
capacity]; head++;
return item;
}}
Art of Multiprocessor
19
Programming
Defining concurrent queue
implementations
• Need a way to specify a concurrent
queue object
• Need a way to prove that an
algorithm implements the object’s
specification
• Lets talk about object specifications
…
Art of Multiprocessor
Programming
20
Correctness and Progress
• In a concurrent setting, we need to
specify both the safety and the liveness
properties of an object
• Need a way to define
– when an implementation is correct
– the conditions under which it guarantees
progress
Lets begin with correctness
Art of Multiprocessor
Programming
21
Sequential Objects
• Each object has a state
– Usually given by a set of fields
– Queue example: sequence of items
• Each object has a set of methods
– Only way to manipulate state
– Queue example: enq and deq methods
Art of Multiprocessor
Programming
22
Sequential Specifications
• If (precondition)
– the object is in such-and-such a state
– before you call the method,
• Then (postcondition)
– the method will return a particular value
– or throw a particular exception.
• and (postcondition, con’t)
– the object will be in some other state
– when the method returns,
Art of Multiprocessor
Programming
23
Pre and PostConditions for
Dequeue
• Precondition:
– Queue is non-empty
• Postcondition:
– Returns first item in queue
• Postcondition:
– Removes first item in queue
Art of Multiprocessor
Programming
24
Pre and PostConditions for
Dequeue
• Precondition:
– Queue is empty
• Postcondition:
– Throws Empty exception
• Postcondition:
– Queue state unchanged
Art of Multiprocessor
Programming
25
Why Sequential Specifications
Totally Rock
• Interactions among methods captured by
side-effects on object state
– State meaningful between method calls
• Documentation size linear in number of
methods
– Each method described in isolation
• Can add new methods
– Without changing descriptions of old methods
Art of Multiprocessor
Programming
26
What About Concurrent
Specifications ?
• Methods?
• Documentation?
• Adding new methods?
Art of Multiprocessor
Programming
27
Methods Take Time
time
Art of Multiprocessor
Programming
28
Methods Take Time
invocation
12:00
q.enq(...)
time
Art of Multiprocessor
Programming
29
Methods Take Time
invocation
12:00
q.enq(...)
Method call
time
Art of Multiprocessor
Programming
30
Methods Take Time
invocation
12:00
q.enq(...)
Method call
time
Art of Multiprocessor
Programming
31
Methods Take Time
invocation
12:00
response
12:01
q.enq(...)
void
Method call
time
Art of Multiprocessor
Programming
32
Sequential vs Concurrent
• Sequential
– Methods take time? Who knew?
• Concurrent
– Method call is not an event
– Method call is an interval.
Art of Multiprocessor
Programming
33
Concurrent Methods Take
Overlapping Time
time
Art of Multiprocessor
Programming
34
Concurrent Methods Take
Overlapping Time
Method call
time
Art of Multiprocessor
Programming
35
Concurrent Methods Take
Overlapping Time
Method call
Method call
time
Art of Multiprocessor
Programming
36
Concurrent Methods Take
Overlapping Time
Method call
Method call
Method call
time
Art of Multiprocessor
Programming
37
Sequential vs Concurrent
• Sequential:
– Object needs meaningful state only
between method calls
• Concurrent
– Because method calls overlap, object might
never be between method calls
Art of Multiprocessor
Programming
38
Sequential vs Concurrent
• Sequential:
– Each method described in isolation
• Concurrent
– Must characterize all possible interactions
with concurrent calls
• What if two enqs overlap?
• Two deqs? enq and deq? …
Art of Multiprocessor
Programming
39
Sequential vs Concurrent
• Sequential:
– Can add new methods without affecting
older methods
• Concurrent:
– Everything can potentially interact with
everything else
Art of Multiprocessor
Programming
40
Sequential vs Concurrent
• Sequential:
– Can add new methods without affecting
older methods
• Concurrent:
– Everything can potentially interact with
everything else
Art of Multiprocessor
Programming
41
The Big Question
• What does it mean for a concurrent
object to be correct?
– What is a concurrent FIFO queue?
– FIFO means strict temporal order
– Concurrent means ambiguous temporal
order
Art of Multiprocessor
Programming
42
Intuitively…
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
Art of Multiprocessor
Programming
43
Intuitively…
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
All modifications
lock.unlock();
of queue are done
}
mutually exclusive
}
Art of Multiprocessor
Programming
44
Intuitively
Lets capture the idea of describing
the concurrent via the sequential
lock()
q.deq
q.enq
lock()
enq
time
enq
unlock()
deq
unlock()
deq
Art of Multiprocessor
Programming
Behavior is
“Sequential”
45
Linearizability
• Each method should
– “take effect”
– Instantaneously
– Between invocation and response events
• Object is correct if this “sequential”
behavior is correct
• Any such concurrent object is
– Linearizable™
Art of Multiprocessor
Programming
46
Is it really about the object?
• Each method should
– “take effect”
– Instantaneously
– Between invocation and response events
• Sounds like a property of an
execution…
• A linearizable object: one all of whose
possible executions are linearizable
Art of Multiprocessor
Programming
47
Example
time
(6)
Art of Multiprocessor
Programming
48
Example
q.enq(x)
time
(6)
Art of Multiprocessor
Programming
49
Example
q.enq(x)
q.enq(y)
time
(6)
Art of Multiprocessor
Programming
50
Example
q.enq(x)
q.enq(y)
q.deq(x)
time
(6)
Art of Multiprocessor
Programming
51
Example
q.enq(x)
q.enq(y)
q.deq(y)
q.deq(x)
time
(6)
Art of Multiprocessor
Programming
52
Example
q.enq(x)
q.enq(y)
q.deq(y)
q.deq(x)
time
(6)
Art of Multiprocessor
Programming
53
Example
q.enq(x)
q.enq(y)
q.deq(y)
q.deq(x)
time
(6)
Art of Multiprocessor
Programming
54
Example
time
(5)
Art of Multiprocessor
Programming
55
Example
q.enq(x)
time
(5)
Art of Multiprocessor
Programming
56
Example
q.enq(x)
q.deq(y)
time
(5)
Art of Multiprocessor
Programming
57
Example
q.enq(x)
q.deq(y)
q.enq(y)
time
(5)
Art of Multiprocessor
Programming
58
Example
q.enq(x)
q.deq(y)
q.enq(y)
time
(5)
Art of Multiprocessor
Programming
59
Example
q.enq(x)
q.deq(y)
q.enq(y)
time
(5)
Art of Multiprocessor
Programming
60
Example
time
(4)
Art of Multiprocessor
Programming
61
Example
q.enq(x)
time
(4)
Art of Multiprocessor
Programming
62
Example
q.enq(x)
q.deq(x)
time
(4)
Art of Multiprocessor
Programming
63
Example
q.enq(x)
q.deq(x)
time
(4)
Art of Multiprocessor
Programming
64
Example
q.enq(x)
q.deq(x)
time
(4)
Art of Multiprocessor
Programming
65
Example
q.enq(x)
time
(8)
Art of Multiprocessor
Programming
66
Example
q.enq(x)
q.enq(y)
time
(8)
Art of Multiprocessor
Programming
67
Example
q.enq(x)
q.deq(y)
q.enq(y)
time
(8)
Art of Multiprocessor
Programming
68
Example
q.enq(x)
q.deq(y)
q.enq(y)
q.deq(x)
time
(8)
Art of Multiprocessor
Programming
69
Comme ci Example
Comme ça
q.enq(x)
q.deq(y)
q.enq(y)
q.deq(x)
time
Art of Multiprocessor
Programming
70
Read/Write Register Example
write(0)
read(1)
write(2)
write(1)
read(0)
time
(4)
Art of Multiprocessor
Programming
71
Read/Write Register Example
write(0)
read(1)
write(2)
write(1)
read(0)
write(1) already
happened time
(4)
Art of Multiprocessor
Programming
72
Read/Write Register Example
write(0)
read(1)
write(2)
write(1)
read(0)
write(1) already
happened time
(4)
Art of Multiprocessor
Programming
73
Read/Write Register Example
write(0)
read(1)
write(2)
write(1)
read(0)
write(1) already
happened time
(4)
Art of Multiprocessor
Programming
74
Read/Write Register Example
write(0)
read(1)
write(2)
write(1)
read(1)
write(1) already
happened time
(4)
Art of Multiprocessor
Programming
75
Read/Write Register Example
write(0)
read(1)
write(2)
write(1)
read(1)
write(1) already
happened time
(4)
Art of Multiprocessor
Programming
76
Read/Write Register Example
write(0)
read(1)
write(2)
write(1)
read(1)
write(1) already
happened time
(4)
Art of Multiprocessor
Programming
77
Read/Write Register Example
write(0)
write(2)
write(1)
read(1)
time
(4)
Art of Multiprocessor
Programming
78
Read/Write Register Example
write(0)
write(2)
write(1)
read(1)
time
(4)
Art of Multiprocessor
Programming
79
Read/Write Register Example
write(0)
write(2)
write(1)
read(1)
time
(4)
Art of Multiprocessor
Programming
80
Read/Write Register Example
write(0)
read(1)
write(2)
write(1)
read(1)
time
(2)
Art of Multiprocessor
Programming
81
Read/Write Register Example
write(0)
read(1)
write(2)
write(1)
read(1)
time
(2)
Art of Multiprocessor
Programming
82
Read/Write Register Example
write(0)
read(1)
write(2)
write(1)
read(1)
time
(2)
Art of Multiprocessor
Programming
83
Read/Write Register Example
write(0)
read(1)
write(2)
write(1)
read(2)
time
(2)
Art of Multiprocessor
Programming
84
Talking About Executions
• Why?
– Can’t we specify the linearization point of
each operation without describing an
execution?
• Not Always
– In some cases, linearization point depends
on the execution
Art of Multiprocessor
Programming
85
Formal Model of Executions
• Define precisely what we mean
– Ambiguity is bad when intuition is weak
• Allow reasoning
– Formal
– But mostly informal
• In the long run, actually more important
• Ask me why!
Art of Multiprocessor
Programming
86
Split Method Calls into Two
Events
• Invocation
– method name & args
– q.enq(x)
• Response
– result or exception
– q.enq(x) returns void
– q.deq() returns x
– q.deq() throws empty
Art of Multiprocessor
Programming
87
Invocation Notation
A q.enq(x)
(4)
Art of Multiprocessor
Programming
88
Invocation Notation
A q.enq(x)
thread
(4)
Art of Multiprocessor
Programming
89
Invocation Notation
A q.enq(x)
thread
(4)
method
Art of Multiprocessor
Programming
90
Invocation Notation
A q.enq(x)
thread
method
object
(4)
Art of Multiprocessor
Programming
91
Invocation Notation
A q.enq(x)
thread
method
object
(4)
Art of Multiprocessor
Programming
arguments
92
Response Notation
A q: void
(2)
Art of Multiprocessor
Programming
93
Response Notation
A q: void
thread
(2)
Art of Multiprocessor
Programming
94
Response Notation
A q: void
thread
(2)
result
Art of Multiprocessor
Programming
95
Response Notation
A q: void
thread
result
object
(2)
Art of Multiprocessor
Programming
96
Response Notation
A q: void
thread
result
object
(2)
Art of Multiprocessor
Programming
97
Response Notation
A q: empty()
thread
exception
object
(2)
Art of Multiprocessor
Programming
98
History - Describing an Execution
A
A
A
H = B
B
B
B
q.enq(3)
q:void
q.enq(5)
p.enq(4)
p:void
q.deq()
q:3
Art of Multiprocessor
Programming
Sequence of
invocations and
responses
99
Definition
• Invocation & response match if
Object names
agree
Thread
names agree
A q.enq(3)
A q:void
(1)
Art of Multiprocessor
Programming
Method call
100
Object Projections
H=
A
A
B
B
B
B
q.enq(3)
q:void
p.enq(4)
p:void
q.deq()
q:3
Art of Multiprocessor
Programming
101
Object Projections
H|q =
A
A
B
B
B
B
q.enq(3)
q:void
p.enq(4)
p:void
q.deq()
q:3
Art of Multiprocessor
Programming
102
Thread Projections
H=
A
A
B
B
B
B
q.enq(3)
q:void
p.enq(4)
p:void
q.deq()
q:3
Art of Multiprocessor
Programming
103
Thread Projections
H|B =
A
A
B
B
B
B
q.enq(3)
q:void
p.enq(4)
p:void
q.deq()
q:3
Art of Multiprocessor
Programming
104
Complete Subhistory
A
A
A
H = B
B
B
B
q.enq(3)
q:void
q.enq(5)
p.enq(4)
p:void
q.deq()
An invocation is
q:3
pending if it has no
matching response
Art of Multiprocessor
Programming
105
Complete Subhistory
A
A
A
H = B
B
B
B
q.enq(3)
q:void
q.enq(5)
p.enq(4)
p:void
q.deq()
May or may not
q:3
have taken effect
Art of Multiprocessor
Programming
106
Complete Subhistory
A
A
A
H = B
B
B
B
q.enq(3)
q:void
q.enq(5)
p.enq(4)
p:void
q.deq()
q:3
Art of Multiprocessor
Programming
discard pending
invocations
107
Complete Subhistory
A q.enq(3)
A q:void
Complete(H) = B
B
B
B
p.enq(4)
p:void
q.deq()
q:3
Art of Multiprocessor
Programming
108
Sequential Histories
A
A
B
B
B
B
A
q.enq(3)
q:void
p.enq(4)
p:void
q.deq()
q:3
q:enq(5)
(4)
Art of Multiprocessor
Programming
109
Sequential Histories
A
A
B
B
B
B
A
q.enq(3)
q:void
p.enq(4)
p:void
q.deq()
q:3
q:enq(5)
(4)
match
Art of Multiprocessor
Programming
110
Sequential Histories
A
A
B
B
B
B
A
q.enq(3)
q:void
p.enq(4)
p:void
q.deq()
q:3
q:enq(5)
(4)
match
match
Art of Multiprocessor
Programming
111
Sequential Histories
A
A
B
B
B
B
A
q.enq(3)
q:void
p.enq(4)
p:void
q.deq()
q:3
q:enq(5)
(4)
match
match
match
Art of Multiprocessor
Programming
112
Sequential Histories
A
A
B
B
B
B
A
q.enq(3)
q:void
p.enq(4)
p:void
q.deq()
q:3
q:enq(5)
(4)
match
match
match
Final pending
invocation OK
Art of Multiprocessor
Programming
113
Sequential Histories
A
A
B
B
B
B
A
q.enq(3)
q:void
p.enq(4)
p:void
q.deq()
q:3
q:enq(5)
(4)
match
match
match
Final pending
invocation OK
Art of Multiprocessor
Programming
114
Well-Formed Histories
A
B
B
H= B
A
B
q.enq(3)
p.enq(4)
p:void
q.deq()
q:void
q:3
Art of Multiprocessor
Programming
115
Well-Formed Histories
Per-thread
projections sequential
A
B
B
H= B
A
B
q.enq(3)
p.enq(4)
p:void
q.deq()
q:void
q:3
B
H|B= B
B
B
Art of Multiprocessor
Programming
p.enq(4)
p:void
q.deq()
q:3
116
Well-Formed Histories
Per-thread
projections sequential
A
B
B
H= B
A
B
q.enq(3)
p.enq(4)
p:void
q.deq()
q:void
q:3
B
H|B= B
B
B
p.enq(4)
p:void
q.deq()
q:3
A q.enq(3)
H|A=
A q:void
Art of Multiprocessor
Programming
117
Equivalent Histories
Threads see the same
thing in both
A
B
B
H= B
A
B
q.enq(3)
p.enq(4)
p:void
q.deq()
q:void
q:3
H|A = G|A
H|B = G|B
A
A
B
G= B
B
B
Art of Multiprocessor
Programming
q.enq(3)
q:void
p.enq(4)
p:void
q.deq()
q:3
118
Sequential Specifications
• A sequential specification is some way
of telling whether a
– Single-thread, single-object history
– Is legal
• For example:
– Pre and post-conditions
– But plenty of other techniques exist …
Art of Multiprocessor
Programming
119
Legal Histories
• A sequential (multi-object) history H is
legal if
– For every object x
– H|x is in the sequential spec for x
Art of Multiprocessor
Programming
120
Precedence
A
B
B
A
B
B
q.enq(3)
p.enq(4)
p.void
q:void
q.deq()
q:3
A method call precedes
another if response
event precedes
invocation event
Method call
(1)
Art of Multiprocessor
Programming
Method call
121
Non-Precedence
A
B
B
B
A
B
q.enq(3)
p.enq(4)
p.void
q.deq()
q:void
q:3
Some method calls
overlap one another
Method call
Method call
(1)
Art of Multiprocessor
Programming
122
Notation
• Given
– History H
– method executions m0 and m1 in H
• We say m0 H m1, if
– m0 precedes m1
• Relation m0 H m1 is a
m0
m1
– Partial order
– Total order if H is sequential
Art of Multiprocessor
Programming
123
Linearizability
• History H is linearizable if it can be
extended to G by
– Appending zero or more responses to
pending invocations
– Discarding other pending invocations
• So that G is equivalent to
– Legal sequential history S
– where G  S
Art of Multiprocessor
Programming
124
What is G  S
G = {ac,bc}
S = {ab,ac,bc}
a
b
G
time
(8)
Art of Multiprocessor
Programming
c
S
125
Remarks
• Some pending invocations
– Took effect, so keep them
– Discard the rest
• Condition G  S
– Means that S respects “real-time order” of
G
Art of Multiprocessor
Programming
126
Example
A
B
B
B
B
B
q.enq(3)
q.enq(4)
q:void
q.deq()
q:4
q:enq(6)
A. q.enq(3)
B.q.enq(4)
B.q.deq(4)
B. q.enq(6)
time
Art of Multiprocessor
Programming
127
Example
A
B
B
B
B
B
q.enq(3)
q.enq(4)
q:void
q.deq()
q:4
q:enq(6)
Complete this
pending
invocation
A. q.enq(3)
B.q.enq(4)
B.q.deq(3)
B. q.enq(6)
time
Art of Multiprocessor
Programming
128
Example
A
B
B
B
B
B
A
q.enq(3)
q.enq(4)
q:void
q.deq()
q:4
q:enq(6)
q:void
Complete this
pending
invocation
A.q.enq(3)
B.q.enq(4)
B.q.deq(4)
B. q.enq(6)
time
Art of Multiprocessor
Programming
129
Example
discard this one
A
B
B
B
B
B
A
q.enq(3)
q.enq(4)
q:void
q.deq()
q:4
q:enq(6)
q:void
A.q.enq(3)
B.q.enq(4)
B.q.deq(4)
B. q.enq(6)
time
Art of Multiprocessor
Programming
130
Example
discard this one
A
B
B
B
B
q.enq(3)
q.enq(4)
q:void
q.deq()
q:4
A q:void
A.q.enq(3)
B.q.enq(4)
B.q.deq(4)
time
Art of Multiprocessor
Programming
131
Example
A
B
B
B
B
A
q.enq(3)
q.enq(4)
q:void
q.deq()
q:4
q:void
A.q.enq(3)
B.q.enq(4)
B.q.deq(4)
time
Art of Multiprocessor
Programming
132
Example
A
B
B
B
B
A
q.enq(3)
q.enq(4)
q:void
q.deq()
q:4
q:void
B
B
A
A
B
B
q.enq(4)
q:void
q.enq(3)
q:void
q.deq()
q:4
A.q.enq(3)
B.q.enq(4)
B.q.deq(4)
time
Art of Multiprocessor
Programming
133
Example
Equivalent sequential history
A
B
B
B
B
A
q.enq(3)
q.enq(4)
q:void
q.deq()
q:4
q:void
B
B
A
A
B
B
q.enq(4)
q:void
q.enq(3)
q:void
q.deq()
q:4
A.q.enq(3)
B.q.enq(4)
B.q.deq(4)
time
Art of Multiprocessor
Programming
134
Composability Theorem
• History H is linearizable if and only if
– For every object x
– H|x is linearizable
• We care about objects only!
– (Materialism?)
Art of Multiprocessor
Programming
135
Why Does Composability Matter?
• Modularity
• Can prove linearizability of objects in
isolation
• Can compose independently-implemented
objects
Art of Multiprocessor
Programming
136
Reasoning About
Linearizability: Locking
head
public T deq() throws EmptyException {
1
capacity-1 y
z
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
tail
0
Art of Multiprocessor
Programming
2
137
Reasoning About
Linearizability: Locking
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
Linearization points
lock.unlock();
}
are when locks are
}
released
Art of Multiprocessor
Programming
138
More Reasoning: Wait-free
head
head
public class WaitFreeQueue {
capacity-1
capacity-1
int head = 0, tail = 0;
items = (T[]) new Object[capacity];
0
0
tail
tail
1
yy zz
1
2
2
public void enq(Item x) {
if (tail-head == capacity) throw
new FullException();
items[tail % capacity] = x; tail++;
}
public Item deq() {
if (tail == head) throw
new EmptyException();
Item item = items[head % capacity]; head++;
return item;
}}
Art of Multiprocessor
139
Programming
More Reasoning: Wait-free
public class WaitFreeQueue {
head
tail
Linearization order is
y z
tail = 0;
order head and tail
new Object[capacity];
fields modified
0
int head = 0,
items = (T[])
capacity-1
1
2
public void enq(Item x) {
if (tail-head == capacity) throw
new FullException();
items[tail % capacity] = x; tail++;
}
public Item deq() {
if (tail == head) throw
new EmptyException();
Item item = items[head % capacity]; head++;
return item;
}}
Art of Multiprocessor
140
Programming
Strategy
• Identify one atomic step where method
“happens”
– Critical section
– Machine instruction
• Doesn’t always work
– Might need to define several different
steps for a given method
Art of Multiprocessor
Programming
141
Linearizability: Summary
• Powerful specification tool for shared
objects, good for high level objects
(composability)
• Allows us to capture the notion of
objects being “atomic”
• Operation takes effect instantaneously
between invocation and response
• Uses sequential specification
• Don’t leave home without it
Art of Multiprocessor
Programming
142
Progress
• We saw an implementation whose
methods were lock-based (deadlockfree)
• We saw an implementation whose
methods did not use locks (lock-free)
• How do they relate?
Art of Multiprocessor
Programming
143
Progress Conditions
• Deadlock-free: some thread trying to acquire
the lock eventually succeeds.
• Starvation-free: every thread trying to
acquire the lock eventually succeeds.
• Lock-free: some thread calling a method
eventually returns.
• Wait-free: every thread calling a method
eventually returns.
Art of Multiprocessor
Programming
144
Progress Conditions
Blocking
Non-Blocking
Everyone
makes
progress
Wait-free
Starvation-free
Someone
makes
progress
Lock-free
Deadlock-free
Art of Multiprocessor
Programming
145
This work is licensed under a Creative Commons AttributionShareAlike 2.5 License.
•
•
•
•
•
You are free:
– to Share — to copy, distribute and transmit the work
– to Remix — to adapt the work
Under the following conditions:
– Attribution. You must attribute the work to “The Art of
Multiprocessor Programming” (but not in any way that suggests that
the authors endorse you or your use of the work).
– Share Alike. If you alter, transform, or build upon this work, you
may distribute the resulting work only under the same, similar or a
compatible license.
For any reuse or distribution, you must make clear to others the license
terms of this work. The best way to do this is with a link to
– http://creativecommons.org/licenses/by-sa/3.0/.
Any of the above conditions can be waived if you get permission from
the copyright holder.
Nothing in this license impairs or restricts the author's moral rights.
Art of Multiprocessor
Programming
146