Пытаясь понять простые вещи 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 гарантирует, что действие происходит атомарно, даже если требуется несколько ходов, прежде чем он сможет сделать это успешно.

  1. threadDelay уже возвращает (), нет необходимости явно return () позже
  2. newTVarIO это краткая версия atomically . newTVar,
  3. Это более читабельно, если вы используете forever вместо того, чтобы хвастаться, как в commandProcessor,

Что касается вашего вопроса, ответ "да". Он называется live-lock, в котором у вашего потока есть работа, но он не может прогрессировать. Представьте себе действительно дорогую функцию, expensiveи действительно дешевая функция, cheap, Если они работают в конкурирующих atomically блоки на том же TVar тогда дешевая функция может вызвать expensive функция никогда не завершать. Я построил пример для соответствующего вопроса SO.

Ваш закрывающий пример не совсем прав, хотя, если операция STM никогда не завершается, то putStrLn никогда не будет достигнут, и никакого вывода не будет видно из этого потока.

Другие вопросы по тегам