Проблема монады STM
Это всего лишь гипотетический сценарий, иллюстрирующий мой вопрос. Предположим, что между ними есть два потока и один TVar. В одном потоке есть атомарный блок, который читает TVar и занимает 10 секунд. В другом потоке есть атомарный блок, который модифицирует TVar каждую секунду. Будет ли завершен первый атомный блок? Конечно, он просто продолжит возвращаться к началу, потому что журнал постоянно находится в противоречивом состоянии?
3 ответа
Как уже говорили другие: в теории нет гарантии прогресса. На практике также нет гарантии прогресса:
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" в моих тестах.
Очевидно, что если вы думаете, что вычисления все еще будут правильными / уместными, то вы захотите либо
- Оставьте атомарный блок, выполните дорогостоящие вычисления, введите атомный блок / подтвердите предположения, действительные / и обновите значение. Потенциально опасно, но не более, чем большинство стратегий блокировки.
- Запомните результаты в атомарном блоке, так что все еще действительный результат будет не более чем дешевым поиском после повторной попытки.
STM предотвращает тупик, но все еще уязвим для голода. В патологическом случае для 1-го атомного действия возможно всегда добывать ресурс.
Тем не менее, изменения происходят очень редко - я не думаю, что когда-либо видел это на практике.
Семантику см. В разделе " Операции с составной памятью", раздел 6.5 "Ход выполнения". STM в Haskell гарантирует только то, что работающая транзакция будет успешно зафиксирована (т.е. не будет тупиковой), но в худшем случае бесконечная транзакция заблокирует другие.
Нет, все будет хорошо. Как именно будут взаимодействовать два потока, зависит от логики повторения.
Например, скажем, у вас есть:
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
msgstr "поток будет в состоянии повтора, пока TVar не достигнет значения 7, затем он продолжится.
Обратите внимание, что вы не можете напрямую контролировать, сколько времени эти вычисления займут в монаде STM. Это было бы побочным эффектом, и побочные эффекты не допускаются в вычислениях STM. Единственный способ общения с внешним миром - через значения, передаваемые через транзакционную память.
А это означает, что если логика "передачи эстафетной палочки" через транзакционную память верна, программа будет работать правильно независимо от того, сколько именно времени она занимает. Это часть гарантии STM.