Question

Je me suis coincé dans la compréhension du concept de atomiquement dans STM.

J'illustre avec un exemple

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

La sortie de l'échantillon serait comme ceci:

Résultat d'ajouter dans 1 Vrai Résultat d'add dans 4 Résultat Faux d'ajouter dans 1 FalseResult d'ajouter dans 2 FalseResult de ajouter 3 Faux Bonjour tout le monde? Résultat de ajouter 4 Faux

Résultat d'ajouter à 1 FalseResult d'ajouter dans 2 Résultat Faux d'ajouter dans 3 Faux Résultat d'ajouter dans 4 False

Résultat d'ajouter dans 1 Résultat Faux d'ajouter dans 2 FalseResult d'ajouter dans 3 FalseResult d'ajouter dans 4 Faux

Résultat d'ajouter dans 1 Résultat Faux d'ajouter dans 2 FalseResult d'ajouter dans 3 FalseResult d'ajouter dans 4 Faux

Résultat d'ajouter dans 1 Résultat Faux d'ajouter dans 2 FalseResult d'ajouter à 4 FalseResult d'ajouter dans 3 Faux

Résultat d'ajouter dans 1 Résultat Faux d'ajouter en 4 FalseResult d'ajouter dans 2 FalseResult d'ajouter dans 3 Faux

Résultat d'ajouter à 1 FalseResult d'ajouter dans 4 Résultat Faux d'ajouter dans 2 Faux Résultat d'ajouter dans 3 Faux

Résultat d'ajouter à 1 FalseResult d'ajouter en 4 Faux

Résultat d'ajouter dans 2 FalseResult des add dans 3 Faux

Résultat d'ajouter à 1 FalseResult d'ajouter en 4 Faux

Résultat d'ajouter dans 2 FalseResult des add dans 3 Résultat Faux d'ajouter dans 1 Faux Résultat d'ajouter dans 4 False

Résultat d'ajouter dans 2 FalseResult des add dans 3 Faux

Résultat d'ajouter à 1 FalseResult d'ajouter en 4 Faux

Quand je lis à propos atomiquement

. Cela signifie que toutes les opérations à l'intérieur de la transaction entièrement complète, sans aucun autre fils modifier les variables que notre transaction utilise, ou il tombe en panne, et l'état est annulée à l'endroit où il était avant que la transaction a commencé. En bref, les transactions atomiques soit complète entièrement, ou il est comme si elles ne fonctionnent pas du tout.

Donc la question pourrait le « retour » de succ dans certains cas, ne jamais se produire? C'est possible la ligne succ <- atomiquement runAdd $ d putStrLn $ "Résultat d'ajouter dans" ++ (montrer i) ++ "" ++ (succ show)

donner une sortie de « Résultat d'ajouter à? I » ( « comme si elles ne manquent jamais du tout »)

Était-ce utile?

La solution

Si une transaction ne soit annulée, ce qui se passe est que votre programme essaie à nouveau. Vous pouvez imaginer la mise en œuvre de atomically être quelque chose comme ceci:

atomically action = do varState <- getStateOfTVars
                       (newState, ret) <- runTransactionWith action varState
                       success <- attemptToCommitChangesToTVars newState
                       if success
                         then return ret
                         else atomically action -- try again

Dans votre cas, la transaction sera toujours courir et sera toujours complète. Il peut compléter le deuxième ou troisième tentative en raison de conflits, mais que vous est invisible pour l'utilisateur. STM veille à ce que l'action se atomiquement, même si cela prend quelques essais avant qu'il ne soit en mesure de le faire avec succès.

Autres conseils

  1. threadDelay déjà des retours (), pas besoin de explicitement return () après
  2. newTVarIO est une version concise de atomically . newTVar.
  3. Il est plus facile à lire si vous utilisez forever au lieu de la queue vous appeler comme cela se fait dans commandProcessor.

Quant à votre question, la réponse est « oui ». Il est appelé verrou en direct dans lequel votre fil a du travail à faire, mais il ne peut pas faire des progrès. Imaginez une fonction vraiment cher, expensive, et une fonction vraiment pas cher, cheap. Si ceux-ci fonctionnent en concurrence des blocs de atomically sur la même TVar alors la fonction peut entraîner la pas cher fonction expensive de ne jamais complète. Je construit un exemple pour un lié ??SO question .

Votre exemple de fermeture n'est pas tout à fait raison que, si l'opération STM ne se termine jamais alors putStrLn ne sera jamais atteint et aucune sortie visible du tout de ce fil.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top