software transactional memory (stm) in frege
TRANSCRIPT
STMSoftware Transactional Memory
in Frege - a purely functional JVM language
Parallel 2016, Heidelberg
Dierk König Canoo
mittie
Goal: make you curiousHow to program with STM
How STM works in principle
The benefits of STM
How Frege keeps you safe
Silly Clock
10010 every ms
on overflow
every so often
Transactional Variables
10010
CounterCounter
millissecs
TVar Int
Create new TVartype Counter = TVar Int
newCounter :: STM CounternewCounter = TVar.new 0
STM action type
Read & Write TVartick :: Counter -> STM ()tick counter = do value <- counter.read counter.write (value + 1)
STM action (no IO)
Check transaction invariantmaxTick :: Counter -> Int -> STM ()maxTick counter max = do tick counter value <- counter.read check (value <= max)
Composition !
Consistent updateonOverflow :: Counter->Counter->Int->STM ()onOverflow counter overflowCounter max = do value <- counter.read check (value == max) tick overflowCounter reset counter
Composition !
Type of reset enforcedreset :: Counter -> STM ()reset counter = counter.write 0
must be STM action
Atomicallyreport :: Counter -> Counter -> IO ()report millis secs = do (millisValue, secsValue) <- atomically $ do a <- millis.read b <- secs.read return (a, b) println $ show secsValue ++ " " ++ show millisValue
Transaction demarcation calls STM action inside IO action
Starting the threadsmain _ = do millis <- atomically newCounter secs <- atomically newCounter milliOverflow = 1000 runTicker = maxTick millis milliOverflow runSec = onOverflow millis secs milliOverflow
forkOS $ forever (atomically runTicker >> Thread.sleep 1) forkOS $ forever (atomically runSec ) forever (report millis secs >> Thread.sleep 100)
STMWorks like compare and swap but for all TVars inside an atomically functionplus invariants (check)plus alternatives (orElse)plus proper exception handling
No user-managed locks -> No deadlocks
First one wins
isolated work commit
failretry
Problem with locksIssue Risk
Too few locks Race conditions
Wrong lock order Deadlock
Too many locks Less throughput
Lock leakage Breaks modularity
Less concurreny errorsSTM replaces all your locks just like GC replaces manual memory management
Makes compositional and modular code
Is optimistic and thus works best in low contention scenarios
Is not a panacea (sorry).
You must notUse TVars outside a transaction
Do side effects inside a transaction no REST calls, no DB access, no file system access, no I/0 at all (time, threads, random), no object mutation, not even a „harmless“ println!
Developer Discipline
Pure Functional Language
code inspection type system
Pure Transactions
Type inference FTW
Classic: Account transferdeposit :: Account -> Int -> STM ()deposit account amount = do balance <- account.read account.write (balance + amount)
withdraw :: Account -> Int -> STM ()withdraw account amount = deposit account (- amount) -- composed
limitedWithdraw :: Account -> Int -> STM ()limitedWithdraw account amount = do withdraw account amount -- composed balance <- account.read check (balance >= 0)
transfer :: Account -> Account -> Int -> STM ()transfer from to amount = do limitedWithdraw from amount -- composed deposit to amount -- composed
Classic: Ant colony
AntsFood Pheromones Evaporation Reporter
Frege STM summaryNo access to TVars outside transactionsNo side effects inside transactions
TYPE SYSTEM (pure FP)Developer discipline (everybody else)
www.frege-lang.org is the only option on the JVM
Dierk König canoo
mittie
Please give feedback!
Credits Volker Steiss master thesis Simon Peyton-Jones Beautiful concurrency