B3CC: Concurrency 05: Software Transactional Memory (1) Trevor L. - - PowerPoint PPT Presentation

b3cc concurrency 05 software transactional memory 1
SMART_READER_LITE
LIVE PREVIEW

B3CC: Concurrency 05: Software Transactional Memory (1) Trevor L. - - PowerPoint PPT Presentation

B3CC: Concurrency 05: Software Transactional Memory (1) Trevor L. McDonell Utrecht University, B2 2020-2021 Announcement From next week (Nov 30) we will o ff er the online werkcollege: - Monday 13:15 - 15:00 - Thursday 9:00 - 10:45 As


slide-1
SLIDE 1

B3CC: Concurrency 05: Software Transactional Memory (1)

Trevor L. McDonell Utrecht University, B2 2020-2021

slide-2
SLIDE 2

Announcement

  • From next week (Nov 30) we will offer the online werkcollege:
  • Monday 13:15 - 15:00
  • Thursday 9:00 - 10:45
  • As well as the on-campus werkcollege at the usual time:
  • Tuesday 15:15 - 17:00

2

slide-3
SLIDE 3

Critical sections

3

slide-4
SLIDE 4

Example: bank accounts

  • Model bank accounts and operations like withdrawing, depositing, and

transferring money between accounts

  • It should not be possible to observe a state where, during a transfer, money

has been withdrawn from one account but yet to be deposited into the target account

4

Account 1 $500 Account 2 $300 Account 3 $200

Thread A $150 Thread B $200

slide-5
SLIDE 5

Example: bank accounts

5

Account 1 $500 Account 2 $300 Account 3 $200

Thread A $150 Thread B $200

  • Thread A:
  • Thread B:
slide-6
SLIDE 6

Example: bank accounts

6

Account 1 $500 Account 2 $300 Account 3 $200

Thread A $150 Thread B $200

  • Thread A:
  • Read balance of account 2
  • Thread B:
slide-7
SLIDE 7

Example: bank accounts

7

Account 1 $500 Account 2 $300 Account 3 $200

Thread A $150 Thread B $200

  • Thread A:
  • Read balance of account 2
  • Check for sufficient funds
  • Thread B:
slide-8
SLIDE 8

Example: bank accounts

8

Account 1 $500 Account 2 $300 Account 3 $200

Thread A $150 Thread B $200

  • Thread A:
  • Read balance of account 2
  • Check for sufficient funds
  • Thread B:
  • Read balance of account 2
slide-9
SLIDE 9

Example: bank accounts

9

Account 1 $500 Account 2 $300 Account 3 $200

Thread A $150 Thread B $200

  • Thread A:
  • Read balance of account 2
  • Check for sufficient funds
  • Thread B:
  • Read balance of account 2
  • Check for sufficient funds
slide-10
SLIDE 10

Example: bank accounts

10

Account 1 $500 Account 2 $100 Account 3 $400

Thread A $150 Thread B $200

  • Thread A:
  • Read balance of account 2
  • Check for sufficient funds
  • Thread B:
  • Read balance of account 2
  • Check for sufficient funds
  • Update balance of account 2
slide-11
SLIDE 11

Example: bank accounts

11

Account 1 $650 Account 2 $150 Account 3 $400

Thread A $150 Thread B $200

  • Thread A:
  • Read balance of account 2
  • Check for sufficient funds
  • Update balance of account 2
  • Thread B:
  • Read balance of account 2
  • Check for sufficient funds
  • Update balance of account 2
slide-12
SLIDE 12

Attempt #1

  • The basic idea:

12

type Account = IORef Int deposit ::; Int ->. Account ->. IO () deposit amount acc = do balance <.- readIORef acc writeIORef acc (balance + amount) withdraw ::; Int ->. Account ->. IO () withdraw amount acc = deposit (-amount) acc

slide-13
SLIDE 13

Attempt #2

  • Use locks so that updates are atomic:

13

type Account = MVar Int deposit ::; Int ->. Account ->. IO () deposit amount acc = modifyMVar_ acc $ \balance ->. return (balance + amount)) transfer ::; Int ->. Account ->. Account ->. IO ()
 transfer amount from to = do
 withdraw amount from
 deposit amount to

inconsistent state!

slide-14
SLIDE 14

Attempt #3

  • We need to implement transfer differently

14

type Account = MVar Int transfer ::; Int ->. Account ->. Account ->. IO () transfer amount from to = modifyMVar_ from $ \fromBalance ->. do modifyMVar_ to $ \toBalance ->. return (toBalance + amount) return (fromBalance - amount)

transfer 100 acc1 acc2 transfer 200 acc2 acc1

P0: P1:

slide-15
SLIDE 15

Attempt #4

  • Take locks in an a fixed (but arbitrary) order; release in the opposite order

15

type Account = MVar Int transfer ::; Int ->. Account ->. Account ->. IO () transfer amount from to = if from < to then modifyMVar_ from $ \fromBalance ->. modifyMVar_ to $ \toBalance ->. ..../ else modifyMVar_ to $ \toBalance ->. modifyMVar_ from $ \fromBalance ->. ..../

slide-16
SLIDE 16

Extending the example

  • What happens if we want to…
  • Block (wait) until the from account has sufficient funds?
  • Withdraw from a second account if the first does not have sufficient funds?
  • I hold locks #3 and #5
  • And now need to acquire lock #2, or #4 or…

16

slide-17
SLIDE 17

Locks are bad

  • Problems with locks include:
  • Taking too few locks
  • Taking too many locks
  • Inhibits concurrency (at best) or causes deadlock (at worst)
  • Taking the wrong locks
  • Taking locks in the wrong order
  • Error recovery
  • Lost wake-ups or erroneous retries

17

slide-18
SLIDE 18

Locks are bad

  • The killer:
  • Locks don’t support modular programming
  • We needed to create a new function transfer, rather than using the

(correctly working) functions withdraw and deposit

18

slide-19
SLIDE 19

Atomic blocks

19

slide-20
SLIDE 20

An alternative

  • The idea:
  • Garbage collectors allow us to program without malloc and free;


Can we do the same for locks? What would that look like?

  • Modular concurrency!
  • Locks are pessimistic; let’s be optimistic instead

20

slide-21
SLIDE 21

Software transactional memory

  • A technique for implementing atomic blocks
  • Atomicity: effects become visible to other threads all at once
  • Isolation: cannot see the effects of other threads
  • Use a different type to wrap operations whose effects can be undone if

necessary (more on this later)

21

import Control.Concurrent.STM data STM a --. abstract instance Monad STM --. among other things atomically ::; STM a ->. IO a

slide-22
SLIDE 22

Software transactional memory

  • Sharing state
  • Instead of IORef, we use TVar as a transactional variable
  • Basic interface:

22

import Control.Concurrent.STM.TVar newTVar ::; a ->. STM (TVar a) readTVar ::; TVar a ->. STM a writeTVar ::; TVar a ->. a ->. STM ()

slide-23
SLIDE 23

Software transactional memory

  • Sharing state
  • Instead of MVar we have an equivalent TMVar
  • A variable is either full or empty: threads wait for the appropriate state
  • Basic interface:

23

import Control.Concurrent.STM.TMVar newTMVar ::; a ->. STM (TMVar a) newEmptyTMVar ::; STM (TMVar) readTMVar ::; TMVar a ->. STM a writeTMVar ::; TMVar a ->. a ->. STM ()

slide-24
SLIDE 24

Revisiting accounts

  • STM actions are composed together in the same way as IO actions

24

type Account = TVar Int deposit ::; Int ->. Account ->. STM () deposit amount account = do balance <.- readTVar account writeTVar (balance + amount) account withdraw ::; Int ->. Account ->. STM () withdraw amount = deposit (-amount)

slide-25
SLIDE 25

Revisiting accounts

  • STM actions are executed as a single, isolated atomic block

25

transfer ::; Int ->. Account ->. Account ->. IO () transfer amount from to = atomically $ do withdraw amount from deposit amount to

slide-26
SLIDE 26

STM

  • Types are used to isolate transactional actions from arbitrary IO actions
  • To get from STM to IO we have to execute the entire action atomically
  • Can’t mix monads!

26

bad ::; Int ->. Account ->. STM () bad amount account = do putStrLn “withdrawing!” --. ::; IO () withdraw amount account --. ::; STM () good ::; Int ->. Account ->. IO () good amount account = do putStrLn “withdrawing!” --. ::; IO () atomically $ withdraw amount account --. ::; IO ()

slide-27
SLIDE 27

Implementing transactional memory

  • How to implement atomically
  • Single global lock?
  • Instead: optimistic execution, without taking any locks
  • At the start of the atomic block begin a thread local transaction log
  • Each writeTVar records the address and the new value to the log
  • Each readTVar searches the log and
  • Takes the value of an earlier writeTVar; or
  • Reads the TVar and records the value into the log

27

slide-28
SLIDE 28

Implementing transactional memory

  • At the end of the atomic block the transaction log must be validated
  • Checks each readTVar in the log matches the current value
  • If successful all writeTVar recorded in the log are committed to the real

TVars

  • The validate and commit steps must be truly atomic

28

slide-29
SLIDE 29

Implementing transactional memory

  • What if validation fails?
  • The operation executed with an inconsistent view of memory
  • Re-execute the transaction with a new transaction log
  • Since none of the writes are committed to memory, this is safe to do
  • It is critical that the atomic block contains no actions other than reads

and writes to TVars

29

atomically $ do x <.- readTVar xv y <.- readTVar yv if x > y then brexit --. ::; IO () side effects! else return ()

slide-30
SLIDE 30

Summary (so far)

  • STM gives us:
  • Atomic transactions for shared memory
  • Encapsulation of concurrent code
  • Help avoid common locking problems
  • But…
  • Just like garbage collection, is no silver bullet
  • Can not solve all problems: e.g. starvation & contention

30

slide-31
SLIDE 31

Photo by JC Gellidon

tot ziens