Haskell STM Idea
Software transactional memory is a way to change shared boxes together, as one step. It lets threads share data without holding a lock by hand.
One TVar change lands as a single step
Start with 10. Add 5 inside one transaction.
import Control.Concurrent.STM
main :: IO ()
main = do
t <- newTVarIO (10 :: Int)
atomically $ modifyTVar' t (+ 5)
v <- readTVarIO t
print vTwo boxes change together
Start with 10 and 20. Change both inside one transaction.
import Control.Concurrent.STM
main :: IO ()
main = do
a <- newTVarIO (10 :: Int)
b <- newTVarIO (20 :: Int)
atomically $ do
modifyTVar' a (+ 3)
modifyTVar' b (+ 4)
x <- readTVarIO a
y <- readTVarIO b
print (x, y)A flag and a count change together
Start with a count of 0 and a flag of False. Set both inside one transaction.
import Control.Concurrent.STM
main :: IO ()
main = do
count <- newTVarIO (0 :: Int)
flag <- newTVarIO False
atomically $ do
writeTVar count 5
writeTVar flag True
c <- readTVarIO count
f <- readTVarIO flag
print (c, f)Example
import Control.Concurrent.STM
main :: IO ()
main = do
a <- newTVarIO (100 :: Int)
b <- newTVarIO (50 :: Int)
atomically $ do
modifyTVar' a (subtract 30)
modifyTVar' b (+ 30)
x <- readTVarIO a
y <- readTVarIO b
print (x, y)Key points
- STM: software transactional memory changes shared boxes as one step.
- Shared box: a box that more than one thread can read and change.
- Transaction: a group of reads and writes that happens all at once or not at all.
- Atomically: the function atomically runs a transaction so no other thread sees it half done.
- Conflict: two transactions clash when they change the same box at the same time.
In this example, two accounts start at 100 and 50. One transaction takes 30 from the first and adds 30 to the second. The main thread reads both back and prints 70 and 80.
Note
STM retries a clashing transaction instead of locking the box by hand.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Haskell Playground
Exercise
What does atomically guarantee about a transaction?