Haskell STMの単純なことを理解しようとしています
-
28-10-2019 - |
質問
私は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 of add in 2 falseresult of add in 3 false hello world? 4 falseの追加の結果
追加の結果1 falserest of add in 2 false add in 3 false add in fals
追加の結果1のaddのaddの2 falseresult in 3 falseresult in add in 4 fals
追加の結果1のaddのaddの2 falseresult in 3 falseresult in add in 4 fals
追加の結果1のaddのaddの2 falseresult in 4 falseresult in add in 3 fals
追加の結果1のaddのadd in4 falseresult in 2 falseresult in add in 3 fals
追加の結果1 falserest of add in 4 false add in 2 false add in 3 false
追加の結果1 falseresult of add in 4 false
追加の結果2 falseresult of add in 3 false
追加の結果1 falseresult of add in 4 false
追加の結果2 falserest of add in 3 false add in add in 1 false add in 4 fals
追加の結果2 falseresult of add in 3 false
追加の結果1 falseresult of add in 4 false
原子について読んだとき
. 。これは、トランザクション内のすべての操作が完全に完了することを意味します。他のスレッドでは、トランザクションが使用している変数を変更するか、失敗し、状態はトランザクションが開始される前の場所に戻ります。要するに、アトミックトランザクションは完全に完了するか、まるでそれらがまったく実行されなかったかのようです。
それで、質問に、場合によってはサクスの「戻り」が起こらないでしょうか?それは、ラインがコセクルである可能性があります<-tomatically $ runadd d putstrln $ "add in" ++(show i)++ "" ++(show cuck)
「add in?i」の出力を与える(「まるで彼らがまったく実行されなかったかのように」)
解決
トランザクションがロールバックされた場合、何が起こるかが、プログラムが再び試みることです。の実装を想像できます 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は、アクションが原子的に発生することを確認します。
他のヒント
threadDelay
既にreturn()、明示的に必要ありませんreturn ()
その後newTVarIO
の簡潔なバージョンですatomically . newTVar
.- 使用すれば読みやすくなります
forever
テールが自分を完成させたとおりに呼ぶ代わりにcommandProcessor
.
あなたの質問に関しては、答えは「はい」です。それはあなたのスレッドにやるべきことがあるが、それは進歩することはできないライブロックと呼ばれています。本当に高価な機能を想像してください、 expensive
, 、そして本当に安い機能、 cheap
. 。これらが競合する場合 atomically
同じことにブロック TVar
その後、安価な機能が原因となります expensive
決して完了しない機能。 aの例を作成しました 関連する質問.
ただし、STM操作が完了しない場合、閉鎖の例はまったく正しくありません putStrLn
決して到達することはなく、そのスレッドから出力はまったく見られません。