试图理解Haskell STM简单的事情

时间:2011-02-02 08:56:53

标签: haskell ghc transactional-memory

我无法理解STM中原子的概念。

我用一个例子来说明

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

示例输出如下:

  

添加1的结果添加的结果   在4个虚假结果中加1   添加2个FalseResult的FalseResult   添加3个假世界?的结果   加4错误

     

添加1个FalseResult of add的结果   in 2 False Result of add in 3 False   添加4 False的结果

     

添加1的结果添加的结果   在2个FalseResult中添加3个   FalseResult of add in 4 False

     

添加1的结果添加的结果   在2个FalseResult中添加3个   FalseResult of add in 4 False

     

添加1的结果添加的结果   在2个FalseResult中添加4个   FalseResult of add in 3 False

     

添加1的结果添加的结果   在4 FalseResult中添加2   FalseResult of add in 3 False

     

添加1个FalseResult of add的结果   4个虚假结果加2个假   添加3个错误的结果

     

添加1个FalseResult of add的结果   在4错误

     

添加2个FalseResult of add的结果   3错误

     

添加1个FalseResult of add的结果   在4错误

     

添加2个FalseResult of add的结果   in 3 False Result of add in 1 False   添加4 False的结果

     

添加2个FalseResult of add的结果   3错误

     

添加1个FalseResult of add的结果   在4错误

当我读到原子的时候

  

。这意味着事务内的所有操作都完全完成,没有任何其他线程修改我们的事务正在使用的变量,或者它失败,并且状态被回滚到事务开始之前的状态。简而言之,原子事务要么完全完成,要么就好像它们根本就不运行一样。

所以对于这个问题,在某些情况下succ的“返回”是否永远不会发生? 那就行了  succ&lt; - atomically $ runAdd d   putStrLn $“加入的结果”++(show i)++“”++(show succ)

输出“加入的结果?i”(“好像它们根本没有运行”)

2 个答案:

答案 0 :(得分:7)

如果事务确实被回滚,那么会发生什么事情是您的程序再次尝试。你可以想象atomically的实现是这样的:

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

在您的情况下,交易将始终运行并始终完成。由于冲突,它可能在第二次或第三次尝试时完成,但是对于您(用户)来说这是不可见的。 STM确保动作以原子方式发生,即使在能够成功完成之前需要花费一些时间。

答案 1 :(得分:2)

  1. threadDelay已经返回(),之后无需明确return ()
  2. newTVarIOatomically . newTVar
  3. 的简明版本
  4. 如果您使用forever而不是像commandProcessor中所做的那样使用尾部调用,则更具可读性。
  5. 至于你的问题,答案是肯定的。它被称为live-lock,你的线程可以在其中工作,但它无法取得进展。想象一个非常昂贵的函数expensive和一个非常便宜的函数cheap。如果它们在同一atomically上的竞争TVar块中运行,则廉价函数可能导致expensive函数永远不会完成。我为related SO question建立了一个示例。

    你的结束例子并不完全正确,如果STM操作永远不会完成,那么永远不会到达putStrLn,并且根本不会看到该线程的输出。