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
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
- 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.
- 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.
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.
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
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. –
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.
Gracias por la referencia. – Alex
Los STM no son necesariamente no bloqueantes. –
- 1. ¿En qué se diferencia Clojure STM de Haskell STM?
- 2. mónada
- 3. Continuación mónada "interfaz" mónada "interfaz"
- 4. Resultado de la mónada dentro del transformador de mónada
- 5. Actualización mónada exterior sólo en el transformador mónada
- 6. Mónada de estado en OCaml
- 7. Biblioteca hash STM para C (glib?)
- 8. Clojure STM (dosync) x bloque de sincronización de Java
- 9. Subyacente Parsec Mónada
- 10. Ascensor transformador mónada ErrorT
- 11. Mónada función unirse
- 12. Haskell: FIFO mónada
- 13. Es jQuery una mónada
- 14. Stackoverflow en mónada continuación
- 15. lector Mónada con Scalaz
- 16. ¿Por qué el transformador de mónada ListT se considera defectuoso? ¿Qué leyes de mónada se rompen?
- 17. Transformador de mónada para seguimiento de progreso
- 18. función de comprobación de Haskell STM devolviendo undefined
- 19. Utilizando STM y transacciones de base de datos juntas
- 20. scala/akka/stm design for large shared state?
- 21. ¿Experiencias con Clojure STM para grandes conjuntos de datos?
- 22. scalaz validación y mónada lista
- 23. ¿Cómo funciona la mónada ST?
- 24. Ejemplos de mónada de estado de Scalaz
- 25. monoid vs mónada en Scala
- 26. Haskell: hilo bloqueado indefinidamente en una transacción STM
- 27. IO y quizás Interacción de mónada
- 28. ¿Quizás la mónada usa árboles de expresión?
- 29. ¿Debo evitar el uso de la mónada?
- 30. Haskell: ¿Qué mónada acabo de reinventar?
Excelente ejemplo. Quería probar con algo como esto, ¡pero no estaba al tanto de la función 'insafeIOToSTM'! – Alex