DSTM

Software Transactional Memory for
Dynamic-Sized Data Structures
(DSTM – Dynamic STM)
Maurice Herlihy,
Victor Luchangco,
Mark Moir,
William N. Scherer III
PODC 2003
Motivation
• Transactional Memory – simplifies parallel
programming
• STM – Software based TM
– Usually simpler than Hardware based TM
– Can handle situations where HTM fails
• However:
– It is immature (supports static data sets and
static transactions)
– It is complicated
Overview
•
•
•
•
•
•
•
Short recap and what’s new?
How to use DSTM?
Example
Diving into DSTM
Example 2
Improving performance
Obstruction freedom
Transactions
• Transaction – a sequence of steps executed by
a single thread
• Transactions are atomic: each transaction
either commits (it takes effect) or aborts (its
effects are discarded)
• Transactions are linearizable: they appear to
take effect in a one-at-a-time order
The computation model
Starting
transaction
Read-Transactional(o1)
Write-Transactional(o2)
Read(o3)
Write(o4)
Commit-Transaction
The computation model
• Committing a transaction can have two
outcomes:
– Success: the transaction’s operations take effect
– Failure: the operations are discarded
• Implemented in Java and in C++
Previous STM designs
• Only static memory – need to declare the
memory that can be transactioned statically
– We want the ability
and to
thiscreate
is why it istransactional
called Dynamic objects
dynamically
Software Transactional Memory
• Only static transactions – transactions need to
declare which addresses they are going to access
before the transaction begins
– We want to let transactions determine which object
to access based on information of objects read inside
a transaction
Overview
•
•
•
•
•
•
•
Short recap and what’s new?
How to use DSTM?
Example
Diving into DSTM
Example 2
Improving performance
Obstruction freedom
Threads
• A thread that executes transactions must be
inherited from TMThread
Don’t forget the run()
method
class TMThread : Thread {
void beginTransaction();
bool commitTransaction();
void abortTransaction();
}
• Each thread can run a single transaction at a time
Objects (1)
• All transactional objects must implement the
TMCloneable interface:
inteface TMCloneable {
Object clone();
}
• This method clones the object, but clone
implementors don’t need to handle
synchronization issues
Objects (2)
• In order to make an object transactional, need
to wrap it
TMObject
Object
• TMObject is a container for regular Java
objects
Opening an object
• Before using a TMObject in a transaction, it
must be opened
class TMObject {
TMObject(Object obj);
enum Mode {READ, WRITE};
Object open(Mode mode);
}
• An object can either be opened for READ or
WRITE (and read)
Overview
•
•
•
•
•
•
•
Short recap and what’s new?
How to use DSTM?
Example
Diving into DSTM
Example 2
Improving performance
Obstruction freedom
An atomic counter (1)
• The counter has a single data member and
two operations:
class Counter : TMCloneable {
int counterValue = 0;
void inc(); // increment the value
int value(); // returns the value
Object clone();
}
• The object is shared by multiple threads
An atomic counter (2)
Counter counter = new Counter();
TMObject tranCounter = new TMObject(counter);
• When a thread wants to access the counter in
a transaction, it must first open the object
using the encapsulated version:
((TMThread)Thread.currentThread).beginTransaction();
…
Counter counter = (Counter)tranCounter.open(WRITE); Returns true/false to
indicate commit
counter.inc();
status
…
((TMThread)Thread.currentThread).commitTransaction();
Overview
•
•
•
•
•
•
•
Short recap and what’s new?
How to use DSTM?
Example
Diving into DSTM
Example 2
Improving performance
Obstruction freedom
DSTM implementation
• Transactional object structure:
status
transaction
start
TMObject
new object
old object
Data
Locator
Data
Current object version
• The current object version is determined by
the status of the transaction that most
recently opened the object in WRITE mode:
– committed: the new object is the current
– aborted: the old object is the current
– active: the old object is the current, and the new
is tentative
• The actual version only changes when a
commit is successful
Opening an object (1)
• Let's assume transaction A tries to open
object o in WRITE mode.
• Let transaction B be the transaction that most
recently opened o in WRITE mode.
• We need to distinguish between the following
cases:
– B is committed
– B is aborted
– B is active
Opening an object (2) – B committed
committed
transaction
start
o
4
Use CAS in order
to replace locator
Data
new object
old object
Data
B’s
If Locator
CAS fails, A restarts from the
beginning
transaction
active
new object
Data
old object
A’s Locator
1
3
A sets
old aobject
to the previous
creates
new Locator
new
2
A clones the previous new
object, and sets new
clone
Opening an object (3) – B aborted
aborted
transaction
start
o
Data
new object
old object
Data
B’s Locator
4
Use CAS in order
to replace locator
transaction
active
clone
new object
Data
old object
A’s Locator
1
3
A sets
old aobject
to the previous
creates
new Locator
old
2
A clones the previous old object,
and sets new
Opening an object (4) – B active
• Problem: B is active and can either commit or
abort, so which version (old/new) should we
use?
• Answer: A and B are conflicting transactions,
that run at the same time
• Use Contention Manager to decide which
should continue and which should abort
• If B needs to abort, try to change its status to
aborted (using CAS)
Opening an object (5)
• Lets assume transaction A opens object o in
READ mode
– Fetch the current version just as before
– Add the pair (o, v) to the readers list (read-only
table)
Committing a transaction
• The commit needs to do the following:
1. Validate the transaction
2. Change the transaction’s status from active to
committed (using CAS)
Validating transactions
• What?
▫ Validate the objects (only) read by the transaction
• Why?
▫ To make sure that the transaction observes a
If the validation fails, throw an
consistent state
• How?
exception so the user will restart the
transaction from the beginning
1. For each pair (o, v) in the read-only table, verify that
v is still the most recently committed version of o
2. Check that (status == active)
Validation inconsistency
• Assume two threads A and B
Thread A
1. x <- read(o1)
2. w(o2, x + 1)
Thread B
1. y <- read(o2)
2. w(o1, y + 1)
Initially:
o1 = 0
o2 = 0
• If B after A, then o1 = 2, o2 = 1;
• If A after B, then o1 = 1, o2 = 2
• If they run concurrently we can have o1 = 1,
o2 = 1 which is illegal
Conflicts
• Conflicts are detected when:
– A transaction first opens an object and finds that
it is open for modification by another transaction
– When the transaction validates its read set (on
opening an object or commit)
Overview
•
•
•
•
•
•
•
Short recap and what’s new?
How to use DSTM?
Example
Diving into DSTM
Example 2
Improving performance
Obstruction freedom
Ordered Integer List – IntSet (1)
Min
3
4
8
6
Max
Ordered Integer List – IntSet (2)
class List implements TMCloneable {
int value;
TMObject next;
List(int v) { value = v; }
public Object clone() {
List newList = new List(value);
newList.next = next;
return newList;
}
}
Ordered Integer List – IntSet (3)
class IntSet {
TMObject first; // the list’s anchor
IntSet() {
List firstList = new List
(Integer.MIN_VALUE);
first = new TMObject(firstList);
firstList.next = new TMObject(
new List(Integer.MAX_VALUE));
}
}
Ordered Integer List – IntSet (4)
class IntSet {
boolean insert(int v) {
List newList = new List(v);
TMObject newNode = new TMObject(newList);
TMThread thread = Thread.currentThread();
while (true) {
thread.beginTransaction();
boolean result = true;
try {
…
} catch (Denied d) {}
if (thread.commitTransaction())
return result;
}
}
}
Ordered Integer List – IntSet (5)
try {
List prevList = (List)this.first.open(WRITE);
List currList = (List)prevList.next.open(WRITE);
while (currList.value < v) {
prevList = currList;
currList = (List)currList.next.open(WRITE);
}
if (currList.value == v) {
result = false;
} else {
result = true;
newList.next = prevList.next;
prevList.next = newNode;
}
}
Overview
•
•
•
•
•
•
•
Short recap and what’s new?
How to use DSTM?
Example
Diving into DSTM
Example 2
Improving performance
Obstruction freedom
Single entrance
• What is the problem with the previous
example?
• How can it be solved?
– Opening for READ on traversal
– Maybe something more sophisticated?
Releasing an object
• An object that was open for READ can be
released
• What does it imply?
– Careful planning
– Can increase performance
– What happens if we open an object, release it and
open it again in the same transaction?
– Can lead to validation problems
Overview
•
•
•
•
•
•
•
Short recap and what’s new?
How to use DSTM?
Example
Diving into DSTM
Example 2
Improving performance
Obstruction freedom
Non-Blocking Algorithms
• A family of algorithms on a shared data
• Each sub-family satisfies different progress
guarantees
• Usually, there is a correlation between the
progress guarantee strength and the
complexity of the algorithm
Wait-Free algorithms
• An algorithm is wait-free if every operation
has a bound on the number of steps it will
take before completing
No Starvation
Lock-Free algorithms
• An algorithm is lock-free if every step taken
achieves global progress
• Even if n-1 processes fail (while doing
operations on the shared memory), the last
processor can still complete its operation
• Example: Shavit & Touitou’s STM
implementation
Obstruction-Free algorithms
• An algorithm is obstruction-free if at any
point, a single thread executed in isolation for
a bounded number of steps will complete its
operation
• Doesn’t avoid live-locks
• Example: DSTM implementation
• What is it good for?
Contention Manager (CM)
• The contention manager arbitrates between
two conflicting transactions
• Given two (conflicting) transactions TA, TB,
then CM(TA, TB):
1. Decides who wins
2. Decides what the loser should do
(abort/wait/retry)
• Conflicts policy