Domanda

Mi sono bloccato nella comprensione del concetto di atomicamente in STM.

Illustro con un esempio

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

L'output del campione sarebbe così:

Risultato di Aggiungi in 1 vero risultato di Aggiungi in 4 falsi risultati di Aggiungi in 1 falseresult di Aggiungi in 2 falseresult di Add in 3 False Hello World? Risultato di Aggiungi in 4 falsi

Risultato dell'aggiunta in 1 falseresult di Aggiungi in 2 falsi risultato di Aggiungi in 3 falsi risultato di Aggiungi in 4 falsi

Risultato di Aggiungi in 1 falso risultato di Aggiungi in 2 falseresult di Aggiungi in 3 falseresult di Aggiungi in 4 falsi

Risultato di Aggiungi in 1 falso risultato di Aggiungi in 2 falseresult di Aggiungi in 3 falseresult di Aggiungi in 4 falsi

Risultato dell'aggiunta in 1 falso risultato di Aggiungi in 2 falseresult di Aggiungi in 4 falseresult di Aggiungi in 3 falsi

Risultato dell'aggiunta in 1 falso risultato di Aggiungi in 4 falseresult di Aggiungi in 2 falseresult di Aggiungi in 3 falsi

Risultato dell'aggiunta in 1 falseresult di Aggiungi in 4 falsi risultato di Aggiungi in 2 falsi risultato di Aggiungi in 3 falsi

Risultato dell'aggiunta in 1 falseresult di Aggiungi in 4 falsi

Risultato dell'aggiunta in 2 falseresult di Aggiungi in 3 falsi

Risultato dell'aggiunta in 1 falseresult di Aggiungi in 4 falsi

Risultato dell'aggiunta in 2 falseresult di Aggiungi in 3 falsi risultato di Aggiungi in 1 falso risultato di Aggiungi in 4 falsi

Risultato dell'aggiunta in 2 falseresult di Aggiungi in 3 falsi

Risultato dell'aggiunta in 1 falseresult di Aggiungi in 4 falsi

Quando leggo atomicamente

. Ciò significa che tutte le operazioni all'interno della transazione sono completamente complete, senza altri thread che modificano le variabili utilizzate dalla nostra transazione, o non riesce e lo stato viene riportato dove era prima dell'inizio della transazione. In breve, le transazioni atomiche sono complete completamente, o è come se non fossero mai gestite affatto.

Quindi alla domanda il "ritorno" di Succ in alcuni casi non accade mai? Cioè la linea SCET <- atomicamente $ runadd d putstrln $ "risultato dell'aggiunta" ++ (mostra i) ++ "" ++ (mostra succ)

Dai un output di "Risultato dell'aggiunta? I" ("come se non fossero mai gestiti")

È stato utile?

Soluzione

Se una transazione viene ripostata, ciò che succede è che il tuo programma prova di nuovo. Puoi immaginare l'implementazione di atomically Essere qualcosa del genere:

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

Nel tuo caso, la transazione verrà sempre eseguita e completerà sempre. Può completare il secondo o il terzo tentativo a causa di conflitti, ma questo è invisibile per te, l'utente. STM si assicura che l'azione si verifichi atomicamente, anche se ci vuole alcuni prima che sia in grado di farlo con successo.

Altri suggerimenti

  1. threadDelay già ritorna (), non c'è bisogno di esplicito return () in seguito
  2. newTVarIO è una versione concisa di atomically . newTVar.
  3. È più leggibile se usi forever Invece di chiamarti come fatti commandProcessor.

Per quanto riguarda la tua domanda, la risposta è "sì". Si chiama Live-Lock in cui il tuo thread ha un lavoro da fare ma non può fare progressi. Immagina una funzione davvero costosa, expensive, e una funzione davvero economica, cheap. Se questi operano in competizione atomically blocchi sullo stesso TVar quindi la funzione economica può causare il file expensive funzione da non completare mai. Ho costruito un esempio per un correlato quindi domanda.

Il tuo esempio di chiusura non è del tutto giusto, se l'operazione STM non è mai completata allora putStrLn Non sarà mai raggiunto e non verrà visualizzata alcuna emissione da quel thread.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top