1 / 24

Software Transactional Memory

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.

victoria
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. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Software Transactional Memory How D can make concurrent programming a piece of cake Bartosz Milewski D Programming Language

  2. Obvious Things • Multi-Core is here to stay • Programmers must use concurrency • (Dead-) Lock Oriented Programming is BAD • New paradigm badly needed

  3. 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!

  4. 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!

  5. 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

  6. 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!

  7. 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

  8. 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);}

  9. 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 (); }

  10. 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

  11. 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 (); }

  12. 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; }

  13. 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

  14. 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

  15. 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 }

  16. 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; }

  17. 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); }

  18. 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

  19. 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

  20. 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)

  21. 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

  22. Commit Writes • For each location in the write-log • Swap the clone in place of original • Stamp it with write-version • Unlock

  23. D Work • We have C implementation (Brad Roberts’ port of GPL’d Dice, Shalev, and Shalit) • Write D implementation • Modify type system

  24. 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.

More Related