Пытаясь понять простые вещи Haskell STM
Я застрял в понимании атомарного понятия в 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 True Результат добавления в 4 False Результат добавления в 1 False Результ добавления в 2 False Результ добавления в 3 False Hello World? Результат добавления в 4 False
Результат добавления в 1 False Результат добавления в 2 False Результат добавления в 3 False Результат добавления в 4 False
Результат добавления в 1 False Результат добавления в 2 False Результ добавления в 3 False Результата добавления в 4 False
Результат добавления в 1 False Результат добавления в 2 False Результ добавления в 3 False Результата добавления в 4 False
Результат добавления в 1 False Результат добавления в 2 False Результ добавления в 4 False Результ добавления в 3 False
Результат добавления в 1 False Результат добавления в 4 False Результ добавления в 2 False Результ добавления в 3 False
Результат добавления в 1 False Результат добавления в 4 False Результат добавления в 2 False Результат добавления в 3 False
Результат добавления в 1 False Результат добавления в 4 False
Результат сложения в 2 False Результат сложения в 3 False
Результат добавления в 1 False Результат добавления в 4 False
Результат добавления в 2 False Результата добавления в 3 False Результат добавления в 1 False Результат добавления в 4 False
Результат сложения в 2 False Результат сложения в 3 False
Результат добавления в 1 False Результат добавления в 4 False
Когда я читаю об атомно
, Это означает, что все операции внутри транзакции полностью завершены, без каких-либо других потоков, изменяющих переменные, которые использует наша транзакция, или она завершается неудачно, и состояние откатывается до того, где оно было до начала транзакции. Короче говоря, атомарные транзакции либо полностью завершены, либо создается впечатление, что они вообще никогда не выполнялись.
Таким образом, на вопрос, может ли "возврат" succ в некоторых случаях никогда не произойти? То есть может строка succ<- атомарно $ runAdd d putStrLn $ "Результат добавления в" ++ (show i) ++ "" ++ (show succ)
выведите "Result of add in?i " ("как будто они вообще никогда не запускались")
2 ответа
Если транзакция откатывается, то ваша программа пытается снова. Вы можете представить себе реализацию 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
, Если они работают в конкурирующих atomically
блоки на том же TVar
тогда дешевая функция может вызвать expensive
функция никогда не завершать. Я построил пример для соответствующего вопроса SO.
Ваш закрывающий пример не совсем прав, хотя, если операция STM никогда не завершается, то putStrLn
никогда не будет достигнут, и никакого вывода не будет видно из этого потока.