如果 STM 事务失败并重试,是否会调用writeTChan
重新执行,以便最终得到两次写入,或者 STM 仅在事务提交时才实际执行写入?即,这个针对睡觉理发师问题的解决方案是否有效,或者如果交易在enterShop
第一次失败?
import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import System.Random
import Text.Printf
runBarber :: TChan Int -> TVar Int -> IO ()
runBarber haircutRequestChan seatsLeftVar = forever $ do
customerId <- atomically $ readTChan haircutRequestChan
atomically $ do
seatsLeft <- readTVar seatsLeftVar
writeTVar seatsLeftVar $ seatsLeft + 1
putStrLn $ printf "%d started cutting" customerId
delay <- randomRIO (1,700)
threadDelay delay
putStrLn $ printf "%d finished cutting" customerId
enterShop :: TChan Int -> TVar Int -> Int -> IO ()
enterShop haircutRequestChan seatsLeftVar customerId = do
putStrLn $ printf "%d entering shop" customerId
hasEmptySeat <- atomically $ do
seatsLeft <- readTVar seatsLeftVar
let hasEmptySeat = seatsLeft > 0
when hasEmptySeat $ do
writeTVar seatsLeftVar $ seatsLeft - 1
writeTChan haircutRequestChan customerId
return hasEmptySeat
when (not hasEmptySeat) $ do
putStrLn $ printf "%d turned away" customerId
main = do
seatsLeftVar <- newTVarIO 3
haircutRequestChan <- newTChanIO
forkIO $ runBarber haircutRequestChan seatsLeftVar
forM_ [1..20] $ \customerId -> do
delay <- randomRIO (1,3)
threadDelay delay
forkIO $ enterShop haircutRequestChan seatsLeftVar customerId
UPDATE直到上面的事实之后我才注意到hairRequestChan
无论如何,不必成为交易的一部分。我可以用普通的Chan
并做writeChan
in an if
陈述after the atomically
阻止enterShop
。但做出这样的改进就破坏了提出这个问题的全部理由,所以我将其保留在这里。
TChan
操作在提交事务时执行,就像其他 STM 操作一样,因此无论重试事务多少次,您始终都会以单次写入结束。否则它们就毫无用处。
为了说服自己,请尝试这个例子:
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TChan
main = do
ch <- atomically newTChan
forkIO $ reader ch >>= putStrLn
writer ch
reader = atomically . readTChan
writer ch = atomically $ writeTChan ch "hi!" >> retry
这将抛出一个异常,抱怨事务被无限期地阻止。如果writeTChan
如果在事务提交之前发生写入,程序将打印“hi!”在抛出该异常之前。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)