explicit concurrent programming in haskell l.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Explicit Concurrent Programming in Haskell PowerPoint Presentation
Download Presentation
Explicit Concurrent Programming in Haskell

Loading in 2 Seconds...

play fullscreen
1 / 23

Explicit Concurrent Programming in Haskell - PowerPoint PPT Presentation


  • 170 Views
  • Uploaded on

Explicit Concurrent Programming in Haskell . QIAN XI COS597C 10/28/2010. Outline. Recap of IO Monad Thread Primitives Synchronization with Locks Message Passing Channels Software Transactional Memory Transactional Memory with Data Invariants. IO Monad in Haskell. Why Monad?

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

PowerPoint Slideshow about 'Explicit Concurrent Programming in Haskell' - caraf


Download Now 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
outline
Outline
  • Recap of IO Monad
  • Thread Primitives
  • Synchronization with Locks
  • Message Passing Channels
  • Software Transactional Memory
  • Transactional Memory with Data Invariants
io monad in haskell
IO Monad in Haskell
  • Why Monad?
    • Pure functional language needs determinism.

fx = e

f 3

...

f 3

= 7

  • What is Monad?
    • an abstract data type: IO a, e.g. IO Int
    • a container of impure, suspended actions/computations

= 7?

  • How to use Monad?

do encloses a sequence of computations:

an action,

a pattern bounded to the result of an action using <-

a set of local definitions introduced using let

getChar :: IO Char

putChar :: Char -> IO ()

main :: IO ()

main = do c <- getChar

putCharc

creating haskell threads
Creating Haskell Threads
  • forkIO :: IO () -> IO ThreadId

effect-ful

computation

identification of a Haskell thread

must be used in an IO monad

  • Concurrency is “lightweight”: both thread creation and context switching overheads are extremely low.
  • The parent thread will not automatically wait for the child threads to terminate.
  • forkOS :: IO () -> IO ThreadId
    • support certain kinds of foreign calls to external code.

Ex: fibEuler.hs

mutable variable
Mutable Variable
  • Haskell threads communicate through Mvars (mutable variables).
  • MVar writes and reads occur atomically
  • A MVar may be empty or it may contain a value
  • write to occupied MVar, read from empty MVar:
    • will be blocked
    • will be rewoken when it’s empty/ a value is written and try again
    • wake up scheme: FIFO
mvar operations
MVar Operations
  • data MVar a
  • newEmptyMVar :: IO (MVar a)
  • newMVar :: a −> IO (MVar a)
  • takeMVar :: MVar a −> IO a
  • putMVar :: MVar a −> a −> IO ()
  • readMVar :: MVar a −> IO a
  • tryTakeMVar :: MVar a −> IO (Maybe a)
  • tryPutMVar :: MVar a −> a −> IO Bool
  • isEmptyMVar :: MVar a −> IO Bool
example make a rendezvous
Example: Make A Rendezvous

main :: IO()

main

= do aMVar <- newEmptyMVar

bMVar <- newEmptyMVar

doneMVar <- newEmptyMVar

forkIO (threadA aMVar bMVar doneMVar)

forkIO (threadB aMVar bMVar)

takeMVar doneMVar

...

module Main

where

import Control.Concurrent

import Control.Concurrent.MVar

threadA :: MVar String -> MVar String -> MVar Int -> IO()

threadA valueToSendMVar valueReceiveMVar doneMVar

= do

putMVar valueToSendMVar "Are you going trick or treating tonight?”

v <- takeMVar valueReceiveMVar

putMVar doneMVar 1

threadB :: MVar String -> MVar String ->IO()

threadB valueToReceiveMVar valueToSendMVar

= do

z <- takeMVar valueToReceiveMVar

putMVar valueToSendMVar “Yes. Let’s meet at 8pm.”

message passing channels
Message Passing Channels
  • unbounded FIFO channel
  • data Chan a
  • newChan :: IO (Chan a)
  • writeChan :: Chan a -> a -> IO ()
  • readChan :: Chan a -> IO a
  • unGetChan :: Chan a -> a -> IO ()
  • isEmptyChan :: Chan a -> IO Bool
  • dupChan :: Chan a -> IO (Chan a)
  • ...

Ex: chat.hs

haskell stm
Haskell STM
  • Programming with MVar can lead to deadlock
    • one thread is waiting for a value to appear in an MVar
    • no other thread will ever write a value to that MVar
  • An alternative way to synchronize: software transactional memory (STM)
    • A special type of shared variable: TVar
    • TVars are used only inside atomic blocks.
    • The code inside an atomic block is executed as if it were an atomic instruction.
    • Functionally, no other thread is running in parallel/interleaved.
    • In reality, a log is used to roll back execution if conflicts.
tvar operations
TVar Operations
  • data STM a −− A monad supporting atomic memory transactions
  • atomically :: STM a −> IO a −− Perform a series of STM actions atomically
  • data TVar a −− Shared memory locations that support atomic memory operations
  • newTVar :: a −> STM (TVar a) −− Create a new TVar with an initial value
  • readTVar :: TVar a −> STM a −− Return the current value stored in a TVar
  • writeTVar :: TVar a −> a −> STM () −− Write the supplied value into a TVar
slide11

bal :: TVar Int

8

7

Thread 1

1 atomically (do

2v <- readTVar bal

3writeTVar bal (v+1)

4 )

Thread 2

1 atomically (do

2v <- readTVar bal

3writeTVar bal (v-3)

4 )

  • Attempt to commit Thread 2 fails, because value in memory is not consistent with the value in the log
  • Transaction re-runs from the beginning
  • Thread 1 commits
  • Shared bal variable is updated
  • Transaction log is discarded

7

8

7

4

bal

transaction log of Thread 1

transaction log of Thread 2

slide12

bal :: TVar Int

5

8

Thread 1

1 atomically (do

2v <- readTVar bal

3writeTVar bal (v+1)

4 )

Thread 2

1 atomically (do

2v <- readTVar bal

3writeTVar bal (v-3)

4 )

5

transaction log of Thread 2

Ex: simpleSTM.hs

when to use retry and orelse
When To Use retry and orElse?
  • retry :: STM a
    • abort the current transaction
    • re-execute it from the beginning using a fresh log

withdraw :: TVarInt −> Int −> STM ()

withdraw acc n

= do { bal <− readTVar acc;

if bal < n then retry;

writeTVar acc (bal-n)

}

Ex: account.hs

  • orElse :: STM a -> STM a -> STM a
    • compose two transactions
    • if one transaction aborts then the other transaction is executed
    • if it also aborts then the whole transaction is re-executed

atomically (do { withdraw a1 3

‘orElse‘

withdraw a2 3;

deposit b 3 }

)

case study arrayblockingqueue discolo et al flops 06
Case Study: ArrayBlockingQueue (Discolo et al. FLOPS 06)
  • from JSR-166, a java implementation of a fixed length queue
  • select 3 representative interfaces:
    • take: Removes an element from the head of the queue, blocking if the queue is empty
    • peek: Removes an element from the head of the queue if one is immediately available, otherwise return Nothing
    • pullTimeout: Retrives and removes the head of this queue, waiting up to the specified wait time if necessary for an element to become available
data structure
Data Structure

data ArrayBlockingQueueIOe = ArrayBlockingQueueIO{

iempty :: QSem,

ifull :: QSem,

ilock :: MVar (),

ihead :: IORefInt,

itail :: IORefInt,

iused :: IORefInt,

ilen :: Int,

ia :: IOArrayInte

}

data ArrayBlockingQueueSTM e = ArrayBlockingQueueSTM {

shead :: TVar Int,

stail :: TVar Int,

sused :: TVar Int,

slen :: Int,

sa :: Array Int (TVar e)

}

function take
function: take

takeIO :: ArrayBlockingQueueIOe

-> IO e

takeIOabq

= do b <- waitQSem (iemptyabq)

e <- withMVar

(ilockabq)

(\dummy ->

readHeadElementIOabq True)

return e

takeSTM :: ArrayBlockingQueueSTMe

-> IO e

takeSTMabq

= do me <- atomically

( readHeadElementSTMabq

True True)

case me of

Just e -> return e

function peek
function: peek

peekIO :: ArrayBlockingQueueIO e

-> IO (Maybe e)

peekIO abq

= do b <- tryWaitQSem (iempty abq)

if b

then

do me <-

withMVar

(ilock abq)

(\dummy ->

do

u <- readIORef (iused abq)

if u == 0

then return Nothing

else do

e <- readHeadElementIO abq False

return (Just e))

signalQSem (iempty abq)

return me

else return Nothing

peekSTM :: ArrayBlockingQueueSTMe

-> IO (Maybe e)

peekSTMabq

= atomically

(readHeadElementSTMabq False

False)

helper function readheadelement
helper function: readHeadElement

readHeadElementIO ::

ArrayBlockingQueueIOe -> Bool -> IO e

readHeadElementIOabq remove

= do

h <- readIORef (iheadabq)

e <- readArray (iaabq) h

if remove

then do

let len = ilenabq

newh = h `mod` len

u <- readIORef (iusedabq)

writeIORef (iheadabq) newh

writeIORef (iusedabq) (u-1)

signalQSem (ifullabq)

else return ()

return e

readHeadElementSTM ::

ArrayBlockingQueueSTMe -> Bool -> Bool

-> STM (Maybe e)

readHeadElementSTMabq remove block

= do u <- readTVar (susedabq)

if u == 0

then if block

then retry

else return Nothing

else do h <- readTVar (sheadabq)

let tv = saabq ! h

e <- readTVartv

if remove

then do

let len = slenabq

let newh = h `mod` len

writeTVar (sheadabq) $! newh

writeTVar (susedabq) $! (u-1)

else return ()

return (Just e)

a more complex function polltimeout
A More Complex Function: pollTimeout
  • lock-based mechanism has no support for composing two concurrency abstractions

pollTimeoutSTM :: ArrayBlockingQueueSTMe -> TimeDiff -> IO (Maybe e)

pollTimeoutSTMabq timeout

= do c <- startTimerIO timeout

atomically ((do readTChanc

return Nothing)

`orElse`

(do me <- readHeadElementSTMabq True True

return me)

)

performance measurements discolo et al flops 06
Performance Measurements(Discolo et al. FLOPS 06)
  • The test
    • creates an ArrayBlockingQueue of type integer
    • creates an equal number of reader and writer threads that simply loops for the specific number of iterations performing taking or put operations on the queue
    • completes when all threads have terminated
  • For each processor configuration (1-8 processors)
    • varies only the number of reader/writer threads
stm with data invariants
STM with Data Invariants
  • STM can also deal with consistency of the program
  • check E where E is an invariant that should be preserved by every atomic update
  • check :: Bool -> STM a
    • check True = return ()
    • check False = retry
  • account.hs with invariants
references
References
  • “A Tutorial on Parallel and Concurrent Programming in Haskell”, Jones et al., AFP summer school notes, 2008
  • “Lock Free Data Structures using STM in Haskell”, Discolo et al., FLOPS 2006
  • http://haskell.org/haskellwiki/Haskell_for_multicores
  • ...