这只是一个假设的场景来说明我的问题。假设有两个线程,它们之间共享一个TVar。在一个线程中,有一个原子性的块,它读取TVar并花费10秒来完成。在另一个线程中是一个原子块,它每秒修改一次TVar。第一个原子阻塞会完成吗?它肯定会一直回到开头,因为日志永远处于不一致的状态?
发布于 2010-06-14 05:46:23
正如其他人所说:从理论上讲,没有进展的保证。在实践中,也没有进展的保证:
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完成”。
显然,如果您认为计算仍将是有效的/相关的,那么您可能希望
发布于 2010-06-14 05:17:27
STM可以防止死锁,但仍然容易受到饥饿的影响。在病理情况下,1s原子动作总是可以获取资源是可能的。
然而,这种变化是非常罕见的--我不相信我在实践中见过它。
有关语义,请参阅Composable Memory Transactions,第6.5节“进度”。Haskell中的STM只保证正在运行的事务将成功提交(即没有死锁),但在最坏的情况下,无限事务将阻塞其他事务。
发布于 2010-06-13 19:09:51
不,它会工作得很好。这两个线程的交互方式取决于重试逻辑。
例如,假设你有:
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 monad中将花费多长时间。这将是一个副作用,并且在STM计算中不允许有副作用。与外部世界通信的唯一方式是通过通过事务内存传递的值。
这意味着,如果通过事务内存的“接力棒传递”逻辑是正确的,那么程序将独立于其任何部分所需的确切时间而正确地工作。这是STM保证的一部分。
https://stackoverflow.com/questions/3031878
复制相似问题