haskellghctransactional-memory

Trying to understand Haskell STM simple things


I got stuck in understanding the concept of atomically in STM.

I illustrate with an example

import Control.Concurrent
import Control.Concurrent.STM
import Control.Monad
import qualified Data.Map as Map 

main :: IO ()
main =  do
    d <- atomically$ newTVar Map.empty
    sockHandler  d 

sockHandler ::  TVar (Map.Map String Int)-> IO ()
sockHandler  d = do
    forkIO $ commandProcessor  d 1
    forkIO $ commandProcessor  d 2
    forkIO $ commandProcessor  d 3
    forkIO $ commandProcessor  d 4
    forkIO (threadDelay 1000 >> putStrLn "Hello World?")

    threadDelay 10000
    return ()

commandProcessor ::  TVar (Map.Map String Int)-> Int-> IO ()
commandProcessor  d i= do
  addCommand d i
  commandProcessor  d i 

addCommand  ::  TVar (Map.Map String Int) ->Int -> IO ()
addCommand    d i = do
  succ <- atomically $ runAdd d
  putStrLn  $"Result of add in " ++ (show i)++ " " ++( show succ)

runAdd  d =do
  dl <- readTVar d
  let (succ,g)= if   Map.member "a" dl
                  then
                      (False,dl)
                  else
                      (True,Map.insert "a" 9 dl)
  writeTVar d g
  return succ

The sample output would be like this:

Result of add in 1 True Result of add in 4 False Result of add in 1 FalseResult of add in 2 FalseResult of add in 3 False Hello World? Result of add in 4 False

Result of add in 1 FalseResult of add in 2 False Result of add in 3 False Result of add in 4 False

Result of add in 1 False Result of add in 2 FalseResult of add in 3 FalseResult of add in 4 False

Result of add in 1 False Result of add in 2 FalseResult of add in 3 FalseResult of add in 4 False

Result of add in 1 False Result of add in 2 FalseResult of add in 4 FalseResult of add in 3 False

Result of add in 1 False Result of add in 4 FalseResult of add in 2 FalseResult of add in 3 False

Result of add in 1 FalseResult of add in 4 False Result of add in 2 False Result of add in 3 False

Result of add in 1 FalseResult of add in 4 False

Result of add in 2 FalseResult of add in 3 False

Result of add in 1 FalseResult of add in 4 False

Result of add in 2 FalseResult of add in 3 False Result of add in 1 False Result of add in 4 False

Result of add in 2 FalseResult of add in 3 False

Result of add in 1 FalseResult of add in 4 False

When I read about atomically

. This means that all operations inside the transaction fully complete, without any other threads modifying the variables that our transaction is using, or it fails, and the state is rolled back to where it was before the transaction was begun. In short, atomic transactions either complete fully, or it is as if they were never run at all.

So to the question could the "return" of succ in some cases never happen? That is could the line succ <- atomically $ runAdd d putStrLn $"Result of add in " ++ (show i)++ " " ++( show succ)

give an output of "Result of add in ?i " ("as if they were never run at all")


Solution

  • If a transaction does get rolled back, what happens is that your program tries again. You can imagine the implementation of atomically to be something like this:

    atomically action = do varState <- getStateOfTVars
                           (newState, ret) <- runTransactionWith action varState
                           success <- attemptToCommitChangesToTVars newState
                           if success
                             then return ret
                             else atomically action -- try again
    

    In your case, the transaction will always run and will always complete. It may complete on the second or third try due to conflicts, but that's invisible to you, the user. STM makes sure that the action happens atomically, even if it takes a few goes before it's able to do that successfully.