我被困于理解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假你好世界?加4错的结果
加1 FalseResult加2假结果加3假结果加4假结果的结果
加1假结果加在2 FalseResult中加3 FalseResult加4假
加1假结果加在2 FalseResult中加3 FalseResult加4假
加1假结果加在2 FalseResult中加4 FalseResult加3假
加1假结果加在4 FalseResult中加2 FalseResult加3假
加1 FalseResult加4假结果加2假结果加3假结果
加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 $“添加”++ ( show i)++“++ ( show )”的结果。
给出“add in ?i的结果”的输出(“好像根本没有运行它们”)。
发布于 2011-02-02 09:27:53
如果一个事务确实被回滚,那么您的程序将再次尝试。您可以想象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要确保操作是原子性的,即使在它能够成功地做到这一点之前只需要几步就可以了。
发布于 2011-02-03 01:15:04
threadDelay已经返回(),不需要显式地使用return () afterwardnewTVarIO是一个简洁的atomically . newTVar.forever而不是像在commandProcessor.中那样调用自己
至于你的问题,答案是“是”。它被称为活锁,你的线程有工作要做,但它不能取得进展。想象一个非常昂贵的函数,expensive,和一个非常便宜的函数,cheap。如果这些操作在相同的atomically上的竞争TVar块中运行,那么廉价的函数就会导致expensive函数永远不完成。我为一个related SO question建立了一个例子。
但是,如果STM操作始终未完成,则永远不会到达putStrLn,也不会从该线程看到任何输出。
https://stackoverflow.com/questions/4872411
复制相似问题