2010-06-13 22 views
13

Esto es solo un escenario hipotético para ilustrar mi pregunta. Supongamos que hay dos hilos y un TVar compartido entre ellos. En un hilo hay un bloque atómico que lee el TVar y tarda 10 segundos en completarse. En otro hilo hay un bloque atómico que modifica el TVar cada segundo. ¿El primer bloque atómico se completará alguna vez? Seguramente continuará volviendo al principio, porque el registro está perpetuamente en un estado inconsistente.STM problema de mónada

Respuesta

12

Como han dicho otros: en teoría, no hay garantía de progreso. En la práctica, tampoco hay garantía de progreso:

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" 

Lo anterior nunca dice "Hecho con mucho STM" en mis pruebas.

Obviamente, si usted piensa que el cálculo es todavía va a ser válido/pertinente entonces querría cualquiera

  1. dejar el bloque atómica, realice el cálculo caro, entrar en el bloque atómica y/o confirmar las hipótesis son válidas/y actualizar el valor Potencialmente peligroso, pero no más que la mayoría de las estrategias de bloqueo.
  2. Recuerde los resultados en el bloque atómico, por lo que el resultado válido no será más que una búsqueda barata después de un reintento.
+2

Excelente ejemplo. Quería probar con algo como esto, ¡pero no estaba al tanto de la función 'insafeIOToSTM'! – Alex

2

No, funcionaría bien. Exactamente cómo interactuarían los dos hilos depende de la lógica de reintento.

Por ejemplo, digamos que usted tiene:

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 

Así que el "ten" hilo estará en estado de reintento hasta que el TVAR alcanza el valor 7, a continuación, se va a proceder.

Tenga en cuenta que no se puede controlar directamente cuánto tiempo tomarán estos cálculos dentro de la mónada STM. Eso sería un efecto secundario, y los efectos secundarios no son permitidos en los cálculos de STM. La única forma de comunicarse con el mundo exterior es mediante valores pasados ​​a través de la memoria transaccional.

Y eso significa que si la lógica "bastón de mando de paso de" a través de la memoria transaccional es correcta, el programa funciona correctamente, independientemente de la cantidad exacta de tiempo cualquier parte que se necesita. Eso es parte de la garantía de STM.

+0

Realmente estoy pensando en el peor de los casos. Olvidémonos de los experimentos por un momento y solo pensemos en dos hilos, y consideremos la ejecución del STM 'diez'. Lee el TVar y confirma ese valor en el registro. Mientras tanto, el otro hilo cambia ese TVar siempre durante la ejecución de 'diez'.Entonces, al final de la ejecución de 'diez', el valor en el TVar real no es el mismo que el valor leído inicialmente en 'diez', forzando a 'diez' a reiniciar el registro y volver a ejecutarlo todo el tiempo. – Alex

+1

Como dijo Yitz, depende. Sí, es posible construir una situación en la que una transacción nunca se complete. O más formalmente, STM no garantiza el progreso. –

5

STM evita el bloqueo, pero aún es vulnerable a la inanición. Es posible en un caso patológico que la acción atómica 1s adquiera siempre el recurso.

Sin embargo, los cambios de este acontecimiento son muy raros, no creo haberlo visto en la práctica.

Para la semántica, vea Composable Memory Transactions, sección 6.5 "Progreso". STM en Haskell garantiza solo que una transacción en ejecución se comprometerá con éxito (es decir, sin interbloqueo), pero en el peor de los casos, una transacción infinita bloqueará otras.

+0

Gracias por la referencia. – Alex

+0

Los STM no son necesariamente no bloqueantes. –