Пытаясь понять Haskell STM простые вещи - PullRequest
3 голосов
/ 02 февраля 2011

Я застрял в понимании атомарного понятия в 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 FalseResult из добавления в 3 FalseResult добавления в 4 False

Результат добавленияв 1 False Результат добавления в 2 FalseResult добавления в 4 FalseResult добавления в 3 False

Результат добавления в 1 False Результат добавления в 4 FalseResult добавления в 2 FalseResult добавления в 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 FalseResult из добавления в 3 False

результат добавления в 1 FalseResult из добавления в 4 False

Когда я читаю об атомарно

,Это означает, что все операции внутри транзакции полностью завершены, и никакие другие потоки не изменяют переменные, которые использует наша транзакция, или она завершается неудачно, и состояние откатывается до того места, где оно было до начала транзакции.Короче говоря, атомарные транзакции либо полностью завершены, либо это так, как если бы они вообще никогда не выполнялись.

Итак, к какому вопросу в некоторых случаях никогда не может произойти «возврат» succ?То есть может строка succ <- атомарно $ runAdd d putStrLn $ "Результат добавления в" ++ (show i) ++ "" ++ (показать succ) </p>

дать вывод "Результат добавленияin? i "(" как будто они вообще никогда не бегали ")

Ответы [ 2 ]

7 голосов
/ 02 февраля 2011

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

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

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

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

...