2011-02-02 28 views
3

我陷入了理解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)

給輸出「的結果加入?我「(」好像他們從來沒有運行過)「

回答

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確保這項行動能夠以原子級方式進行,即使在能夠成功完成之前需要花費一些時間。

+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

2
  1. threadDelay已經返回(),無需顯式地return()之後
  2. newTVarIOatomically . newTVar一個簡潔的版本。
  3. 如果您使用forever而不是如commandProcessor中所做的那樣調用自己,那麼它更具可讀性。

至於你的問題,答案是肯定的。它被稱爲live-lock,其中你的線程有工作要做,但它不能取得進展。設想一個非常昂貴的功能,expensive,和一個非常便宜的功能,cheap。如果它們在相同的TVar上競爭atomically塊中操作,那麼便宜的功能可能導致功能永遠不會完成。我爲related SO question構建了一個示例。

雖然您的結束示例並不完全正確,但如果STM操作從未完成,那麼永遠不會到達putStrLn,並且根本不會從該線程看到任何輸出。