STM monad问题

Ale*_*lex 13 monads concurrency haskell transactional-memory

这只是一个假设情景来说明我的问题.假设它们之间共享两个线程和一个TVar.在一个线程中有一个原子块来读取TVar并需要10秒才能完成.在另一个线程中是一个原子块,每秒修改一次TVar.第一个原子块是否会完成?当然它会一直回到开头,因为日志永远处于不一致的状态?

Tho*_*son 12

正如其他人所说:理论上并不能保证取得进展.在实践中,也无法保证取得进展:

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"
Run Code Online (Sandbox Code Playgroud)

以上从未在我的测试中说过"做长STM".

显然,如果你认为计算仍然有效/相关,那么你也想要

  1. 离开原子块,执行昂贵的计算,输入原子块/确认假设是有效的/并更新值.潜在的危险,但不比大多数锁定策略更重要.
  2. 在原子块中记住结果,这样在重试后仍然有效的结果将只是一个便宜的查找.

  • 很好的例子.我想用这样的东西测试,但我不知道`unsafeIOToSTM`函数! (2认同)

Don*_*art 5

STM可以防止死锁,但仍然容易受到饥饿的影响.在病态情况下,1s原子动作总是可以获取资源.

然而,这种情况的变化非常罕见 - 我不相信我在实践中见过它.

有关语义,请参阅可组合内存事务,第6.5节"进度".Haskell中的STM仅保证正在运行的事务将成功提交(即没有死锁),但在最坏的情况下,无限事务将阻止其他事务.