STM
concurrencyicon.icon
Haskell’s stm package offers an appealing approach to concurrency:
transactions are guaranteed to be run atomically;
the type system guarantees that transactions can be safely restarted;
there are no locks, hence no danger of deadlocks;
transactional computations are easy to compose, unlike classic lock-based approaches.
The advantages of using STM in concurrent programming are as follows.
Composability : Computation can be composed
Composable blocking gives selectivity
Robustness when there is a failure or cancellation: Easy maintenance of invariant conditions against state
Any STM a typed operation can be combined with other operations to form a large transparent transaction.
Unlike the IO monad, the implementation of STM is designed to roll back the effects of a transaction when there's a conflict with another transaction.
Control.Concurrent.STM.TVar link Shared memory locations that support atomic memory transactions.
code: Control.Concurrent.STM interface.hs
dataSTMa --abstract instance Monad STM dataTVara --abstract
-- transactional variables
newTVar :: a -> STM (TVar a)
newTVarIO :: a -> IO (TVar a)
readTVar :: TVar a -> STM a
writeTVar :: TVar a -> a -> STM ()
-- running a transaction
atomically :: STM a -> IO a
Control.Monad.STM
atomically :: STM a -> IO a
Perform a series of STM actions atomically.
You cannot use atomically inside an unsafePerformIO or unsafeInterleaveIO.
TVar can only be used in STM environment. When atomically is used, STM actions can be executed atomically. You can think of this as executing all the STM monad at once.
TChan
The implementation of TChan is a message queue that holds the first pointer for reading and the last pointer for writing. We create an empty queue (ie communication channel) with newTChan or newTChanIO. writeTChan adds an element to the end of the queue as a message transmission, and readTChan reads elements written by writeTChan from the beginning in order. This means we are performing send and receive messages using the First In First Out (FIFO) method. As a result, message communication is done as asynchronous processing in a not-blocking way.
A thread-safe FIFO queue.
code:TChan.hs
data TChan a --abstract
newTChan :: STM(TChan a)
newBroadcastTChan :: STM(TChan a) --write-only
dupTChan :: TChan a -> STM (TChan a)
readTChan :: TChan a -> STM a
writeTChan :: TChan a -> a -> STM ()
Items written into a channel do not get lost.
Items will be read in the order they have been written (first-in first-out, FIFO).
Items can be read only once (even if accessed concurrently).
dupTChan
code:dupeTchan.hs
dupTChan :: TChan a -> STM (TChan a)
dupTChan (TChan read write) = do
hole <- readTVar write
new_read <- newTVar hole
return (TChan new_read write)
We create a new empty channel.
Items written to the new or original channel will be available on both.
So in this case, any item written can be read twice.
dupTChan creates a new communication channel by copying the pointer at the end of the communication channel (queue). This allows elements written with writeTChan for either communication channel to be shared between both communication channels. On the other hand, readTVar does not affect another communication channel because it reads the value and then only replaces the leading pointer.