Nice example of using Software Transactional Memory. Which is starting to be available in things like gcc, but is much much nicer in Haskell for reasons involving purity and monads.
Particularly this function, which changes a variable in the database, transactionally.
appV :: (DB -> DB) -> TVar DB -> IO ()
appV fn x = atomically $ readTVar x >>= writeTVar x . fn
It would be easy to use this to add commands that eg, increment counters in the database, and the STM would ensure that it works correctly with multiple concurrent writers. No locking needed. A quick example, which could be improved by changing the DB type to support Int as well as String values:
incrCommand :: Handle -> [String] -> (TVar DB) -> IO ()
incrCommand handle k db = do
appV incvar db
hPutStrLn handle $ "OK"
where
incvar k v = insert k $ show $ (fromMaybe 0 $ readMaybe v) + 1
I don't know how well Haskell's STM performs compared with eg, database transactions or locking. It's been more than fast enough for my own needs. Anybody know?
As far as I understand it, this simple example won't perform any better than if it were written using MVar. (i.e. it was explicitly locking reads and writes)
The difference is that `atomically` calls can be nested and still work. If you do an readMVar whilst that MVar is already locked in a function above you in your call stack you would have a deadlock.
So STM seems to be a smart way of keeping track which locks the current execution thread has so you never double lock.
Comments
Nice example of using Software Transactional Memory. Which is starting to be available in things like gcc, but is much much nicer in Haskell for reasons involving purity and monads.
Particularly this function, which changes a variable in the database, transactionally.
It would be easy to use this to add commands that eg, increment counters in the database, and the STM would ensure that it works correctly with multiple concurrent writers. No locking needed. A quick example, which could be improved by changing the DB type to support Int as well as String values: I don't know how well Haskell's STM performs compared with eg, database transactions or locking. It's been more than fast enough for my own needs. Anybody know?As far as I understand it, this simple example won't perform any better than if it were written using MVar. (i.e. it was explicitly locking reads and writes)
The difference is that `atomically` calls can be nested and still work. If you do an readMVar whilst that MVar is already locked in a function above you in your call stack you would have a deadlock.
So STM seems to be a smart way of keeping track which locks the current execution thread has so you never double lock.
At least in this case :)