CSE 230. Concurrency: STM. Slides due to: Kathleen Fisher, Simon Peyton Jones, Satnam Singh, Don Stewart

Similar documents
!!"!#"$%& Atomic Blocks! Atomic blocks! 3 primitives: atomically, retry, orelse!

Simon Peyton Jones (Microsoft Research) Tokyo Haskell Users Group April 2010

COS 326 David Walker. Thanks to Kathleen Fisher and recursively to Simon Peyton Jones for much of the content of these slides.

David Walker. Thanks to Kathleen Fisher and recursively to Simon Peyton Jones for much of the content of these slides.

So#ware Transac-onal Memory. COS 326 David Walker Princeton University

Software Transactional Memory

Composable Shared Memory Transactions Lecture 20-2

PARALLEL AND CONCURRENT PROGRAMMING IN HASKELL

Programming Language Concepts: Lecture 13

COMP3151/9151 Foundations of Concurrency Lecture 8

The future is parallel The future of parallel is declarative. Simon Peyton Jones Microsoft Research

) Intel)(TX)memory):) Transac'onal) Synchroniza'on) Extensions)(TSX))) Transac'ons)

Reminder from last time

CS 2112 Lecture 20 Synchronization 5 April 2012 Lecturer: Andrew Myers

LiU-FP2010 Part II: Lecture 7 Concurrency

Monitors; Software Transactional Memory

Chapter 22. Transaction Management

Tackling Concurrency With STM. Mark Volkmann 10/22/09

Tackling Concurrency With STM

NON-BLOCKING DATA STRUCTURES AND TRANSACTIONAL MEMORY. Tim Harris, 28 November 2014

CMSC 132: Object-Oriented Programming II

Reminder from last time

An Update on Haskell H/STM 1

Multicore programming in Haskell. Simon Marlow Microsoft Research

G Programming Languages Spring 2010 Lecture 13. Robert Grimm, New York University

Transactions. Kathleen Durant PhD Northeastern University CS3200 Lesson 9

) Intel)(TX)memory):) Transac'onal) Synchroniza'on) Extensions)(TSX))) Transac'ons)

Monitors; Software Transactional Memory

Topics. File Buffer Cache for Performance. What to Cache? COS 318: Operating Systems. File Performance and Reliability

Need for synchronization: If threads comprise parts of our software systems, then they must communicate.

Compiler Correctness for Software Transactional Memory

Transactional Memory. Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

CS The IO Monad. Slides from John Mitchell, K Fisher, and S. Peyton Jones

Software Transactions: A Programming-Languages Perspective

) Intel)(TX)memory):) Transac'onal) Synchroniza'on) Extensions)(TSX))) Transac'ons)

Concurrency Control In Distributed Main Memory Database Systems. Justin A. DeBrabant

Advances in Programming Languages

Goldibear and the 3 Locks. Programming With Locks Is Tricky. More Lock Madness. And To Make It Worse. Transactional Memory: The Big Idea

CSE 374 Programming Concepts & Tools

6 Transactional Memory. Robert Mullins

Synchronization. CSCI 5103 Operating Systems. Semaphore Usage. Bounded-Buffer Problem With Semaphores. Monitors Other Approaches

Software System Design and Implementation

The Java Memory Model

Atomicity via Source-to-Source Translation

Synchronization Part II. CS403/534 Distributed Systems Erkay Savas Sabanci University

Programmazione di sistemi multicore

A Pragmatic Case For. Static Typing

Persistent Data Structures and Managed References

Distributed Systems (ICE 601) Transactions & Concurrency Control - Part1

CSE332: Data Abstractions Lecture 23: Programming with Locks and Critical Sections. Tyler Robison Summer 2010

T ransaction Management 4/23/2018 1

Reference types in Clojure. April 2, 2014

Parallel Code Smells: A Top 10 List

Improving STM Performance with Transactional Structs 1

doi: / Composable Memory Transactions By Tim Harris, Simon Marlow, Simon Peyton Jones, and Maurice Herlihy

Atomic Transac1ons. Atomic Transactions. Q1: What if network fails before deposit? Q2: What if sequence is interrupted by another sequence?

Consistency in Distributed Systems

Transaction Management: Concurrency Control, part 2

Locking for B+ Trees. Transaction Management: Concurrency Control, part 2. Locking for B+ Trees (contd.) Locking vs. Latching

Database Management System Prof. D. Janakiram Department of Computer Science & Engineering Indian Institute of Technology, Madras Lecture No.

Introduction to Data Management CSE 344

Synchronization Part 2. REK s adaptation of Claypool s adaptation oftanenbaum s Distributed Systems Chapter 5 and Silberschatz Chapter 17

CS5412: TRANSACTIONS (I)

Lecture 6: Lazy Transactional Memory. Topics: TM semantics and implementation details of lazy TM

Birth of Optimistic Methods. On Optimistic Methods for Concurrency Control. Basic performance arg

CSE 451: Operating Systems Winter Lecture 7 Synchronization. Steve Gribble. Synchronization. Threads cooperate in multithreaded programs

Operating Systems. Sina Meraji U of T

Transaction Management. Pearson Education Limited 1995, 2005

Identity, State and Values

Some Examples of Conflicts. Transactional Concurrency Control. Serializable Schedules. Transactions: ACID Properties. Isolation and Serializability

Programmazione di sistemi multicore

Shared state model. April 3, / 29

Producer Consumer in Ada

The transaction. Defining properties of transactions. Failures in complex systems propagate. Concurrency Control, Locking, and Recovery

CSE332: Data Abstractions Lecture 22: Shared-Memory Concurrency and Mutual Exclusion. Tyler Robison Summer 2010

Lecture 21: Transactional Memory. Topics: consistency model recap, introduction to transactional memory

Potential violations of Serializability: Example 1

Distributed Systems COMP 212. Revision 2 Othon Michail

The concept of concurrency is fundamental to all these areas.

TRANSACTION MEMORY. Presented by Hussain Sattuwala Ramya Somuri

The Problems with OOO

Dealing with Issues for Interprocess Communication

The New Java Technology Memory Model

Comparing the Performance of Concurrent Linked-List Implementations in Haskell

Lecture 20: Transactional Memory. Parallel Computer Architecture and Programming CMU , Spring 2013

10/17/ Gribble, Lazowska, Levy, Zahorjan 2. 10/17/ Gribble, Lazowska, Levy, Zahorjan 4

Lecture 7: Transactional Memory Intro. Topics: introduction to transactional memory, lazy implementation

+ Today. Lecture 26: Concurrency 3/31/14. n Reading. n Objectives. n Announcements. n P&C Section 7. n Race conditions.

3/25/14. Lecture 25: Concurrency. + Today. n Reading. n P&C Section 6. n Objectives. n Concurrency

COMP3151/9151 Foundations of Concurrency Lecture 8

Banking Example (Once Again) CSE 486/586 Distributed Systems Concurrency Control Properties of Transactions: ACID. Transaction. Performance?

CSE 451: Operating Systems Winter Lecture 7 Synchronization. Hank Levy 412 Sieg Hall

CMSC 330: Organization of Programming Languages

I/O in Haskell. To output a character: putchar :: Char -> IO () e.g., putchar c. To output a string: putstr :: String -> IO () e.g.

Database Systems. Announcement

CSE 344 MARCH 5 TH TRANSACTIONS

Synchronization via Transactions

Transactional Events. Kevin Donnelly. Matthew Fluet. Abstract. 1. Introduction. Cornell University

Concurre Concurr nt n Systems 8L for Part IB Handout 3 Dr. Steven Hand 1

CONCURRENCY CONTROL, TRANSACTIONS, LOCKING, AND RECOVERY

Transcription:

CSE 230 Concurrency: STM Slides due to: Kathleen Fisher, Simon Peyton Jones, Satnam Singh, Don Stewart

The Grand Challenge How to properly use multi-cores? Need new programming models!

Parallelism vs Concurrency A parallel program exploits real parallel computing resources to run faster while computing the same answer. Expectation of genuinely simultaneous execution Deterministic A concurrent program models independent agents that can communicate and synchronize. Meaningful on a machine with one processor Non-deterministic

Concurrent Programming Essential For Multicore Performance

Concurrent Programming State-of-the-art is 30 years old! Locks and condition variables Java: synchronized, wait, notify Locks etc. Fundamentally Flawed Building a sky-scraper out of matchsticks

What s Wrong With Locks? Races Forgotten locks lead to inconsistent views Deadlock Locks acquired in wrong order Lost Wakeups Forgotten notify to condition variables Diabolical Error recovery Restore invariants, release locks in exception handlers

Even Worse! Locks Don t Compose class Account{ float balance; synchronized void deposit(float amt) { balance += amt; } } synchronized void withdraw(float amt) { if (balance < amt) throw new OutOfMoneyError(); balance -= amt; } A Correct bank Account class Write code to transfer funds between accounts

Even Worse! Locks Don t Compose 1 st Attempt transfer = withdraw then deposit class Account{ float balance; synchronized void deposit(float amt) { balance += amt; } synchronized void withdraw(float amt) { if(balance < amt) throw new OutOfMoneyError(); balance -= amt; } void transfer(acct other, float amt) { other.withdraw(amt); this.deposit(amt);} }

Even Worse! Locks Don t Compose 1 st Attempt transfer = withdraw then deposit class Account{ float balance; synchronized void deposit(float amt) { balance += amt; } synchronized void withdraw(float amt) { if(balance < amt) throw new OutOfMoneyError(); balance -= amt; } void transfer(acct other, float amt) { other.withdraw(amt); this.deposit(amt);} } Race Condition Wrong sum of balances

Even Worse! Locks Don t Compose 2 st Attempt: synchronized transfer class Account{ float balance; synchronized void deposit(float amt){ balance += amt; } synchronized void withdraw(float amt){ if(balance < amt) throw new OutOfMoneyError(); balance -= amt; } synchronized void transfer(acct other, float amt){ other.withdraw(amt); this.deposit(amt);} }

Even Worse! Locks Don t Compose 2 st Attempt: synchronized transfer class Account{ float balance; synchronized void deposit(float amt){ balance += amt; } synchronized void withdraw(float amt){ if(balance < amt) throw new OutOfMoneyError(); balance -= amt; } synchronized void transfer(acct other, float amt){ other.withdraw(amt); this.deposit(amt);} } Deadlocks with Concurrent reverse transfer

Locks are absurdly hard to get right Scalable double-ended queue: one lock per cell No interference If ends far apart But watch out! If queue is 0, 1, or 2 elements long

Locks are absurdly hard to get right Coding Style Sequential code Difficulty of queue implementation Undergraduate

Locks are absurdly hard to get right Coding Style Sequential code Locks & Conditions Difficulty of queue implementation Undergraduate Major publishable result* *Simple, fast, and practical non-blocking and blocking concurrent queue algorithms

What we have Locks and Conditions: Hard to use & Don t compose Library Hardware

What we want Libraries Build Layered Concurrency Abstractions Library Library Library Library Library Library Library Concurrency primitives Hardware

Idea: Replace locks with atomic blocks Atomic Blocks/STM: Easy to use & Do compose Library Library Library Library Library Library Library Atomic Blocks: atomic, retry, orelse Hardware

Locks are absurdly hard to get right Coding Style Sequential code Locks & Conditions Difficulty of queue implementation Undergraduate Major publishable result* Atomic blocks(stm) Undergraduate *Simple, fast, and practical non-blocking and blocking concurrent queue algorithms

Atomic Memory Transactions cf ACID database transactions atomic {...sequential code...} Wrap atomic around sequential code All-or-nothing semantics: atomic commit

Atomic Memory Transactions cf ACID database transactions atomic {...sequential code...} Atomic Block Executes in Isolation No Data Race Conditions!

Atomic Memory Transactions cf ACID database transactions atomic {...sequential code...} There Are No Locks Hence, no deadlocks!

How it Works atomic {...sequential code...} Optimistic Concurrency Execute code without any locks. Record reads/writes in thread-local transaction log Writes go to the log only, not to memory. At the end, transaction validates the log If valid, atomically commit changes to memory If invalid, re-run from start, discarding changes read y read z write 10 x write 42 z

Why it Doesn t Work atomic {...sequential code...} Logging Memory Effects is Expensive Huge slowdown on memory read/write Cannot Re-Run, Arbitrary Effects How to retract email? How to un-launch missile?

STM in Haskell

Haskell Fits the STM Shoe Haskellers brutally trained from birth to use memory/io effects sparingly!

Issue: Logging Memory Is Expensive Haskell already partitions world into Immutable values (zillions and zillions) Mutable locations (very few) Solution: Only log mutable locations!

Issue: Logging Memory Is Expensive Haskell already paid the bill! Reading and Writing locations are Expensive function calls Logging Overhead Lower than in imperative languages

Issue: Undoing Arbitrary IO Types control where IO effects happen Easy to keep them out of transactions Monads Ideal For Building Transactions Implicitly (invisibly) passing logs

Tracking Effects with Types main = do { putstr (reverse yes ); putstr no } (reverse yes ) :: String -- No effects (putstr no ) :: IO () -- Effects okay Main program is a computation with effects main :: IO ()

Mutable State

Mutable State via the IO Monad newref :: a -> IO (IORef a) readref :: IORef a -> IO a writeref :: IORef a -> a -> IO () Reads and Writes are 100% Explicit (r+6) is rejected as r :: IORef Int

Mutable State via the IO Monad main = do r <- newioref 0 incr r s <- readioref r print s incr :: IORef Int -> IO () incr = do v <- readioref r writeioref r (v+1) newref :: a -> IO (IORef a) readref :: IORef a -> IO a writeref :: IORef a -> a -> IO ()

Concurrency in Haskell forkio function spawns a thread Takes an IO action as argument forkio :: IO a -> IO ThreadId

Concurrency in Haskell main = do r <- newioref 0 forkio $ incr r incr r print s incr :: IORef Int -> IO () incr = do v <- readioref r writeioref r (v+1) Data Race newref :: a -> IO (IORef a) readref :: IORef a -> IO a writeref :: IORef a -> a -> IO () forkio :: IORef a -> IO ThreadId

Atomic Blocks in Haskell atomically :: IO a -> IO a atomically act Executes `act` atomically

Atomic Blocks in Haskell atomically :: IO a -> IO a main = do r <- newref 0 forkio $ atomically $ incr r atomically $ incr r atomic Ensures No Data Races!

Atomic Blocks in Haskell Data Race main = do r <- newref 0 forkio $ incr r atomically $ incr r What if we use incr outside block? Yikes! Races in code inside & outside!

A Better Type for Atomic STM = Trans-actions Tvar = Imperative transaction variables atomic :: STM a -> IO a newtvar :: a -> STM (TVar a) readtvar :: TVar a -> STM a writetvar :: TVar a -> a -> STM () Types ensure Tvar only touched in STM action

Type System Guarantees You cannot forget atomically Only way to execute STM action inct :: TVar Int -> STM () inct r = do v <- readtvar r writetvar r (v+1) main = do r <- atomically $ newtvar 0 TVar forkio $ atomically $ inct r atomically $ inct r...

Type System Guarantees Outside Atomic Block Can t fiddle with TVars Inside Atomic Block Can t do IO, Can t manipulate imperative variables atomic $ if x<y then launchmissiles

Type System Guarantees Note: atomically is a function not a special syntactic construct...and, so, best of all...

(Unlike Locks) STM Actions Compose! inct :: TVar Int -> STM () inct r = do {v <- readtvar r; writetvar r (v+1)} inct2 :: TVar Int -> STM () inct2 r = do {inct r; inct r} foo :: IO () foo =...atomically $ inct2 r... Glue STM Actions Arbitrarily Wrap with atomic to get an IO action Types ensure STM action is atomic

STM Type Supports Exceptions throw :: Exception -> STM a catch :: STM a ->(Exception->STM a)-> STM a No need to restore invariants, or release locks! In `atomically act` if `act` throws exception: 1. Transaction is aborted with no effect, 2. Exception is propagated to enclosing IO code* *Composable Memory Transactions

Transaction Combinators

#1 retry: Compositional Blocking retry :: STM () Abort current transaction & re-execute from start withdraw :: TVar Int -> Int -> STM () withdraw acc n = do bal <- readtvar acc if bal < n then retry writetvar acc (bal-n)

#1 retry: Compositional Blocking retry :: STM () Implementation Avoids Busy Waiting Uses logged reads to block till a read-var (eg. acc) changes withdraw :: TVar Int -> Int -> STM () withdraw acc n = do bal <- readtvar acc if bal < n then retry writetvar acc (bal-n)

#1 retry: Compositional Blocking retry :: STM () No Condition Variables! Uses logged reads to block till a read-var (eg. acc) changes Retrying thread is woken on write, so no forgotten notifies withdraw :: TVar Int -> Int -> STM () withdraw acc n = do bal <- readtvar acc if bal < n then retry writetvar acc (bal-n)

#1 retry: Compositional Blocking retry :: STM () No Condition Variables! No danger of forgetting to test conditions On waking as transaction runs from the start. withdraw :: TVar Int -> Int -> STM () withdraw acc n = do bal <- readtvar acc if bal < n then retry writetvar acc (bal-n)

Why is retry Compositional? Can appear anywhere in an STM Transaction Nested arbitrarily deeply inside a call atomic $ do withdraw a1 3 withdraw a2 7 Waits untill `a1>3` AND `a2>7` Without changing/knowing `withdraw` code

Hoisting Guards Is Not Compositional atomic (a1>3 && a2>7) {...stuff... } Breaks abstraction of...stuff... Need to know code to expose guards

#2 orelse: Choice How to transfer 3$ from a1 or a2 to b? Try this...and if it retries, try this atomically $ do withdraw a1 3`orelse` withdraw a2 3 deposit b 3...and and then do this orelse :: STM a -> STM a -> STM a

Choice Is Composable Too! transfer a1 a2 b = do withdraw a1 3`orElse` withdraw a2 3 deposit b 3 atomically $ transfer a1 a2 b `orelse` transfer a3 a4 b transfer calls orelse But calls to it can be composed with orelse

Ensuring Correctness of Concurrent Accesses? e.g. account should never go below 0

Transaction Invariants Assumed on Entry, Verified on Exit Only Tested If Invariant s TVar changes

#3 always: Enforce Invariants always :: STM Bool -> STM () checkbal :: TVar Int -> STM Bool checkbal v = do cts <- readtvar v return (v > 0) newaccount :: STM (TVar Int) newaccount = do v <- newtvar 0 always $ checkbal v v return v An arbitrary boolean valued STM action Every Transaction that touches acct will check invariant If the check fails, the transaction restarts

#3 always: Enforce Invariants always :: STM Bool -> STM () Adds a new invariant to a global pool Conceptually, all invariants checked on all commits Implementation Checks Relevant Invariants That read TVars written by the transaction

Recap: Composing Transactions A transaction is a value of type STM a Transactions are first-class values Big Tx By Composing Little Tx sequence, choice, block... To Execute, Seal The Transaction atomically :: STM a -> IO a

Complete Implementation in GHC6 Performance is similar to Shared-Var Need more experience using STM in practice You can play with it* Final will have some STM material * Beautiful Concurrency

STM in Mainstream Languages Proposals for adding STM to Java etc. class Account { float balance; void deposit(float amt) { atomic { balance += amt; } } void withdraw(float amt) { atomic { if(balance < amt) throw new OutOfMoneyError(); balance -= amt; } } void transfer(acct other, float amt) { atomic { // Can compose withdraw and deposit. other.withdraw(amt); this.deposit(amt); } } }

Mainstream Types Don t Control Effects So Code Inside Tx Can Conflict with Code Outside! Weak Atomicity Outside code sees inconsistent memory Avoid by placing all shared mem access in Tx Strong Atomicity Outside code guaranteed consistent memory view Causes big performance hit

A Monadic Skin In C/Java, IO is Everywhere No need for special type, all code is in IO monad Haskell Gives You A Choice When to be in IO monad vs when to be purely functional Haskell Can Be Imperative BUT C/Java Cannot Be Pure! Mainstream PLs lack a statically visible pure subset The separation facilitates concurrent programming

Conclusions STM raises abstraction for concurrent programming Think high-level language vs assembly code Whole classes of low-level errors are eliminated. But not a silver bullet! Can still write buggy programs Concurrent code still harder than sequential code Only for shared memory, not message passing There is a performance hit But it seems acceptable, and things can only get better