3

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

サンプル出力は次のようになります。

add in 1 の結果 True add in 4 の結果 False add in 1 の結果 false add in 2 の FalseResult add in 3 False Hello World? 4 False を加算した結果

add in 1 の結果 False add in 2 の結果 False add in 3 の結果 False add in 4 の結果 False

add in 1 の結果 False add in 2 の結果 Falseadd in 3 の結果 Falseadd in 4 の結果 False

add in 1 の結果 False add in 2 の結果 Falseadd in 3 の結果 Falseadd in 4 の結果 False

add in 1 の結果 False add in 2 の結果 Falseadd in 4 の結果 Falseadd in 3 の結果 False

add in 1 の結果 False add in 4 の結果 Falseadd in 2 の結果 Falseadd in 3 の結果 False

add in 1 の結果 False add in 4 の結果 False add in 2 の結果 False add in 3 の結果 False

add in 1 の結果 False add in 4 の結果 False

add in 2 の結果 Falseadd in 3 の結果 False

add in 1 の結果 False add in 4 の結果 False

add in 2 の結果 False add in 3 の結果 False add in 1 の結果 False add in 4 の結果 False

add in 2 の結果 Falseadd in 3 の結果 False

add in 1 の結果 False add in 4 の結果 False

私が原子的に読んだとき

. これは、トランザクションが使用している変数を他のスレッドが変更することなく、トランザクション内のすべての操作が完全に完了するか、またはトランザクションが失敗し、トランザクションが開始される前の状態にロールバックされることを意味します。つまり、アトミック トランザクションは完全に完了するか、まったく実行されていないかのようになります。

では、場合によっては succ の「リターン」が決して起こらないという問題がありますか? つまり、行 succ <- アトミックに $ runAdd d putStrLn $"Result of add in " ++ (show i)++ " " ++( show succ)

「add in ?i の結果」の出力を与える (「まったく実行されなかったかのように」)

4

2 に答える 2

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

あなたの場合、トランザクションは常に実行され、常に完了します。競合が原因で 2 回目または 3 回目の試行で完了する場合がありますが、それはユーザーには見えません。STM は、アクションがアトミックに実行されることを確認します。たとえそれが成功するまでに数回かかるとしてもです。

于 2011-02-02T09:27:53.477 に答える
2
  1. threadDelayすでに()を返します。return ()後で明示的にする必要はありません。
  2. newTVarIOの簡潔なバージョンですatomically . newTVar
  3. foreverで行われたように末尾呼び出しの代わりに使用すると、より読みやすくなりますcommandProcessor

あなたの質問に関しては、答えは「はい」です。これはライブロックと呼ばれ、スレッドに実行する作業がありますが、進行させることはできません。expensive本当に高価な関数、、そして本当に安い関数を想像してみてくださいcheap。これらが同じ上の競合するatomicallyブロックで動作する場合TVar、安価な関数が原因でexpensive関数が完了しない可能性があります。関連するSO質問の例を作成しました。

ただし、最後の例は完全には正しくありません。STM操作が完了しない場合、putStrLn到達することはなく、そのスレッドからの出力はまったく表示されません。

于 2011-02-03T01:15:04.447 に答える