试图了解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确保这项行动能够以原子级方式进行,即使在能够成功完成之前需要花费一些时间。
-
threadDelay
已经返回(),无需显式地return()
之后 -
newTVarIO
是atomically . newTVar
一个简洁的版本。 - 如果您使用
forever
而不是如commandProcessor
中所做的那样调用自己,那么它更具可读性。
至于你的问题,答案是肯定的。它被称为live-lock,其中你的线程有工作要做,但它不能取得进展。设想一个非常昂贵的功能,expensive
,和一个非常便宜的功能,cheap
。如果它们在相同的TVar
上竞争atomically
块中操作,那么便宜的功能可能导致功能永远不会完成。我为related SO question构建了一个示例。
虽然您的结束示例并不完全正确,但如果STM操作从未完成,那么永远不会到达putStrLn
,并且根本不会从该线程看到任何输出。
不错,你有没有这方面的参考? – Jonke 2011-02-02 09:43:00
我发现原始的Haskell-STM文件非常易读,你可以在这里得到一个副本:http://research.microsoft.com/en-us/um/people/simonpj/papers/stm/stm.pdf根据你的例子,我认为只要阅读第三部分和第六部分就足够了,并且应该让你对STM的工作有一个很好的感觉。 – 2011-02-02 10:02:24