【发布时间】:2013-06-05 07:12:37
【问题描述】:
如果一个 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
更新
直到上面的hairRequestChan 无论如何都不必成为交易的一部分,我才注意到。我可以使用常规的Chan 并在if 语句中执行writeChan,在atomically 块中的enterShop 之后。但是做出这种改进会破坏提出这个问题的全部原因,所以我将保持原样。
【问题讨论】: