Software transactional memory
Download
1 / 24

Software Transactional Memory - PowerPoint PPT Presentation


Software Transactional Memory. How D can make concurrent programming a piece of cake Bartosz Milewski D Programming Language. Obvious Things. Multi-Core is here to stay Programmers must use concurrency (Dead-) Lock Oriented Programming is BAD New paradigm badly needed. The Problem.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha

Download Presentation

Software Transactional Memory

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Software Transactional Memory

How D can make concurrent programming a piece of cake

Bartosz Milewski

D Programming Language


Obvious Things

  • Multi-Core is here to stay

  • Programmers must use concurrency

  • (Dead-) Lock Oriented Programming is BAD

  • New paradigm badly needed


The Problem

void Toggle ()

{

if (x == 0)

x = 1;

else

x = 0;

}

  • Fetch value of x

  • Store it in a temporary

  • Compare with zero

  • Based on the result, write new value

What if, in the meanwhile, the original x was modified by another thread?

Write is based on incorrect assumption!


Logically Speaking

  • Theorem:

    • Hypothesis: x == 0 (read x, compare to 0)

    • Conclusion: x = 1 (write 1 into x)

  • Problem: Hypothesis invalidated before conclusion reached

  • Must re-check the hypothesis before writing!


Transaction

  • Delay checking: Log read values for later

  • Must re-check before writing: Log the “intent to write” (speculative writes) for later execution

  • Verify hypothesis : Are read values unchanged?

  • Reach conclusion: Execute writes from log to memory


What Does It Buy Us?

  • Concurrency issues postponed to the commit phase (read-check and write)

  • Commit uses generic code, which can be optimized and tested once for all

  • User code simple, less error-prone—code as if there were a single global lock

  • Increased concurrency—executes as if every word were separately locked

  • No deadlocks!


STM in a Nutshell

  • Start a transaction: create log

  • Speculative execution—reads and writes logged

  • Commit phase (atomic)

    • Read-check

    • Write to memory

  • If failure, restart transaction


Composability

  • Combining atomic operations using locks—almost impossible!

  • Atomic (transacted) withdrawalatomic { acc.Withdraw (sum); }

  • Atomic deposit—similar

  • Atomic transferatomic {accOne.Withdraw (sum);accTwo.Deposit (sum);}


Blocking Transactions

  • Example: Producer/Consumer

atomic

{

Item * item = pcQueue.Get ();

}

Item * Get () atomic // PCQueue method

{

if (_queue.Count () == 0)

retry;

else

return _queue.pop_front ();

}


Retry

  • Restart transaction without destroying the log

  • Make the read-log globally available

  • Block until any of the logged read locations changes

  • Every commit checks the read-sets of blocked transactions and unblocks the ones that overlap with its write-set


The Beauty of Retry

  • Consumer doesn’t have to specify what it’s waiting for

  • Producer doesn’t have to signal anybody

  • Composability: Wait for two items

atomic

{

item1 = pcQueue.Get ();

item2 = pcQueue.Get ();

}


Object-Based STM

  • Transactable (atomic) objects

    • Visible as opaque handles

    • Can be opened only inside transaction

    • Open (for read) returns a const pointer to the actual object

    • Open for write clones the object and returns pointer to the clone

atomic struct Foo { int x; }

atomic Foo f (new Foo); // an opaque handle

atomic { // start transaction

Foo * foo = f.open_write ();

++foo.x;

}


Cloning

  • Deep copy of the object

  • Embedded atomic handles are copied but not the objects they refer to

  • Transactable data structures build from small atomic objects (tree from nodes)

  • Value-semantic objects (e.g. structs) cloned by copy construction


Type System Support

  • Struct or class marked as “atomic”—all methods (except constructor) “atomic”

  • Open and open_write can be called only inside a transaction—i.e. from inside:

    • Atomic block

    • Atomic function/method

  • Atomic function/method may only be called from inside a transaction


Singly-Linked List

struct Slist // not atomic

{

this () {

// Insert sentinels

SNode * last = new SNode (Infin, null);

_head = new SNode (MinusInfin, last);

}

// atomic methods

const (SNode) * Head () const atomic

{

retrun _head.open ();

}

void Insert (int i) atomic;

void Remove (int i) atomic;

private:

atomic SNode _head; // atomic handle

}


Node

struct SNode atomic

{

public:

this (int i, const (SNode) * next) {

_val = i; _next = next;

}

// atomic methods (by default)

int Value () const { return _val; }

const (SNode) * Next () const {

return _next.open ();

}

Snode * SetNext (const (SNode) * next) {

SNode * self = this.open_write ()

self._next = next;

return self;

}

private:

int_val;

atomic Snode_next;

}


Insert

atomic { myList.Insert (x); } // transactioned

void Insert (int i) atomic

{

const (SNode) * prev = Head (); // sentinel

const (SNode) * cur = prev.Next ();

while (cur._val < i)

{

prev = cur;

cur = prev.Next ();

}

assert (cur != 0); // at worst high sentinel

SNode * newNode = new SNode (i, cur);

(void) prev.SetNext (newNode);

}


Implementation

  • Versioning and Locking

    • Global Version Clock (always even)

    • Version numbers always increase

    • (Hidden) version/lock word per atomic object (lock is the lowest bit)

  • Consistent Snapshot maintenance

    • Version checks when opening an object

    • Read-check during commit


Consistent Snapshot

  • Transaction starts by reading Version Clock into the transaction’s read-version variable

  • Open object

    • Check the object lock (bit). If taken, abort

    • Check object version number. If it’s greater than read-version abort


Logging

  • Every open is recorded in read-log

    • Pointer to original object (from which its version lock can be retrieved)

  • Every open_write is recorded in read-log and write_log

    • Pointer to original object

    • Pointer to clone

  • Okay to call open_write after open (read)


Commit

  • Lock all objects recorded in the write-log

    • Bounded spinlock on each version lock

  • Increment global Version Clock—store as transaction’s write-version

  • Sequence Point (if transaction commits, that’s when it “happened”)

  • Read-check

    • Re-check object version numbers against read-version


Commit Writes

  • For each location in the write-log

    • Swap the clone in place of original

    • Stamp it with write-version

    • Unlock


D Work

  • We have C implementation (Brad Roberts’ port of GPL’d Dice, Shalev, and Shalit)

  • Write D implementation

  • Modify type system


Bibliography

  • Dave Dice, Ori Shalev, and Nir Shavit. Transactional Locking II

  • Tim Harris, Simon Marlow, Simon Peyton Jones, and Maurice Herlihy. Composable Memory Transactions. ACM Conference on Principles and Practice of Parallel Programming 2005 (PPoPP'05). 2005.


ad
  • Login