Проблема монады STM

Это просто гипотетический сценарий, чтобы проиллюстрировать мой вопрос. Предположим, что между ними есть два потока и один TVar. В одном потоке есть атомный блок, который читает TVar и забирает 10 секунд. В другом потоке есть атомный блок, который каждую секунду изменяет TVar. Будет ли первый атомный блок когда-либо закончен? Разумеется, он будет продолжать возвращаться к началу, потому что журнал постоянно находится в противоречивом состоянии?

Ответы

Ответ 1

Как говорили другие: в теории нет гарантии прогресса. На практике также нет гарантии прогресса:

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"

Вышеописанное никогда не говорит "Готово с длинным STM" в моих тестах.

Очевидно, если вы считаете, что вычисление все еще будет действительным/уместным, вам нужно либо

  • Оставьте атомный блок, выполните дорогостоящие вычисления, введите значения атомарного блока/подтверждения и/или обновите значение. Потенциально опасный, но не более, чем большинство стратегий блокировки.
  • Запомните результаты в атомном блоке, чтобы все еще действительный результат был не более чем дешевым поиском после повтора.

Ответ 2

STM предотвращает тупик, но все еще уязвим для голодания. В патологическом случае возможно, что атомное действие 1s всегда будет обладать ресурсом.

Однако изменения этого происшествия очень редки - я не верю, что когда-либо видел это на практике.

Для семантики см. Композитные транзакции памяти, раздел 6.5 "Прогресс". STM в Haskell гарантирует только успешную фиксацию текущей транзакции (т.е. Без взаимоблокировки), но в худшем случае бесконечная транзакция блокирует другие.

Ответ 3

Нет, все будет хорошо. Точно как взаимодействие двух потоков зависит от логика повтора.

Например, скажем, у вас есть:

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

Итак, поток ten будет находиться в состоянии повтора до тех пор, пока TVar не достигнет значение 7, то оно будет продолжаться.

Обратите внимание, что вы не можете напрямую контролировать, сколько времени будут выполняться эти вычисления внутри монады STM. Это будет побочным эффектом, и побочные эффекты не допускается в расчетах STM. Единственный способ общения с внешним мир через значения, переданные через транзакционную память.

И это означает, что если логика "baton-pass" через транзакционную память правильно, программа будет работать правильно независимо от точной суммы времени любой его части. Эта часть гарантии STM.