Question

Ceci est juste un scénario hypothétique pour illustrer ma question. Supposons qu'il y a deux fils et une TVAR partagé entre eux. Dans un fil il y a un bloc atomiquement qui lit le tvár et prend 10s pour terminer. Dans un autre thread est un bloc atomiquement qui modifie la tvár chaque seconde. Est-ce que le premier bloc atomiquement jamais terminer? Assurément, il va tout simplement continuer de revenir au début, parce que le journal est perpétuellement dans un état incohérent?

Était-ce utile?

La solution

Comme d'autres ont dit: en théorie, il n'y a aucune garantie de progrès. En pratique, il n'y a également aucune garantie de progrès:

import Control.Monad -- not needed, but cleans some things up
import Control.Monad.STM
import Control.Concurrent.STM
import Control.Concurrent
import GHC.Conc
import System.IO

main = do
    tv <- newTVarIO 0
    forkIO (f tv)
    g tv

f :: TVar Int -> IO ()
f tv = forever $ do
    atomically $ do
            n <- readTVar tv
            writeTVar tv (n + 1)
            unsafeIOToSTM (threadDelay 100000)
    putStr "."
    hFlush stdout

g :: TVar Int -> IO ()
g tv = forever $ do
    atomically $ do
            n <- readTVar tv
            writeTVar tv (n + 1)
            unsafeIOToSTM (threadDelay 1000000)
    putStrLn "Done with long STM"

Le dit ci-dessus ne "fait avec longue STM" dans mes tests.

Il est évident que si vous pensez que le calcul va encore être pertinent de / valide alors vous voulez soit

  1. Laissez le bloc atomique, effectuer des calculs coûteux, saisir les hypothèses bloc atomiques / validation sont valides / et mettre à jour la valeur. Potentiellement dangereux, mais pas plus que la plupart des stratégies de verrouillage.
  2. Memoize les résultats dans le bloc atomique de sorte que le résultat reste valable ne sera plus qu'une recherche pas cher après une nouvelle tentative.

Autres conseils

STM empêche l'impasse, mais est encore vulnérable à la famine. Il est possible dans un cas pathologique pour les 1 action atomique pour toujours la ressource aquire.

Cependant, les changements de ce qui se passe sont très rares - Je ne crois pas que je l'ai jamais vu dans la pratique

.

Pour la sémantique, voir Composable Transactions de mémoire , la section 6.5 "progrès". STM en Haskell ne garantit qu'une transaction en cours d'exécution s'engagera avec succès (à savoir pas une impasse), mais dans le pire des cas, une transaction infinie va bloquer les autres.

Non, cela fonctionnerait bien. Exactement comment Interagir serait les deux fils dépend de la logique de nouvelle tentative.

Par exemple, supposons que vous avez:

ten tv = do
  n <- readTVar tv
  when (n < 7) retry
  writeTVar tv 0
  -- do something that takes about 10 seconds

one tv = do
  modifyTVar tv (+1)
  -- do something that takes about 1 second

le fil « de ten » sera en état de nouvelle tentative jusqu'à ce que le cours de tvár la valeur 7, il procédera.

Notez que vous ne pouvez pas contrôler directement depuis combien de temps ces calculs prendront à l'intérieur du STM monade. Ce serait un effet secondaire, et les effets secondaires ne sont pas permis dans le calcul de la STM. La seule façon de communiquer avec l'extérieur monde se fait par des valeurs transmises par la mémoire transactionnelle.

Cela signifie que si la logique « bâton de passage » à travers la mémoire transactionnelle est correct, le programme fonctionne correctement indépendamment du montant exact de temps une partie de celui-ci prend. Cela fait partie de la garantie de la STM.

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