试图了解Haskell STM简单的东西

问题描述:

我陷入了理解STM中原子的概念。试图了解Haskell 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 FalseResult添加在2 FalseResult的 中添加3个假的Hello World?的 结果中添加在1个FalseResult的4假

结果添加添加 在2假结果的添加在3假 结果添加在添加在添加 1个虚假结果的4假

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

结果添加 在2 FalseResult添加在3 添加的FalseResult的在4假

结果的在1分假的结果添加在添加2 FalseResult在4 添加的FalseResult中添加在添加 1分假的结果的3个假

结果在添加的4 FalseResult在2 的FalseResult添加 添加在添加在1个FalseResult的3假

结果在加入2假 结果添加在3假

结果的4假的结果添加 添加在1 FalseResult的添加 在4假

结果在2 FalseResult的添加 加入的3个假

结果添加在1 FalseResult的添加的 在4假

结果添加2 FalseResult的在附加的3错误结果添加 在1个假 结果的添加在添加的4假

结果在2 FalseResult的添加 在3假

结果的在1中添加的FalseResult添加 在4假

当我读到原子

。这意味着事务内部的所有操作都完全完成,没有任何其他线程修改我们事务正在使用的变量,或者它失败了,状态会回滚到事务开始之前的位置。简而言之,原子事务要么完全完成,要么完全没有运行。

因此,在某些情况下,succ的“返回”可能永远不会发生? 即可以行 SUCC < - 原子$ runAdd d putStrLn $ ++ “中添加的结果”(显示我)++ “” ++(显示SUCC)

给输出“的结果加入?我“(”好像他们从来没有运行过)“

如果事务确实回滚,会发生什么情况是您的程序再次尝试。你可以想像的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确保这项行动能够以原子级方式进行,即使在能够成功完成之前需要花费一些时间。

+0

不错,你有没有这方面的参考? – Jonke 2011-02-02 09:43:00

+1

我发现原始的Haskell-STM文件非常易读,你可以在这里得到一个副本:http://research.microsoft.com/en-us/um/people/simonpj/papers/stm/stm.pdf根据你的例子,我认为只要阅读第三部分和第六部分就足够了,并且应该让你对STM的工作有一个很好的感觉。 – 2011-02-02 10:02:24

  1. threadDelay已经返回(),无需显式地return()之后
  2. newTVarIOatomically . newTVar一个简洁的版本。
  3. 如果您使用forever而不是如commandProcessor中所做的那样调用自己,那么它更具可读性。

至于你的问题,答案是肯定的。它被称为live-lock,其中你的线程有工作要做,但它不能取得进展。设想一个非常昂贵的功能,expensive,和一个非常便宜的功能,cheap。如果它们在相同的TVar上竞争atomically块中操作,那么便宜的功能可能导致功能永远不会完成。我为related SO question构建了一个示例。

虽然您的结束示例并不完全正确,但如果STM操作从未完成,那么永远不会到达putStrLn,并且根本不会从该线程看到任何输出。