STM トランザクションが失敗して再試行した場合、呼び出しwriteTChan
が再実行されて 2 つの書き込みが発生するのでしょうか? それともトランザクションがコミットされた場合に STM が実際に書き込みを実行するだけでしょうか? つまり、寝ている床屋の問題に対するこの解決策は有効でしょうか? それとも、トランザクションenterShop
が最初に失敗した場合、顧客は 2 つのヘアカットを受けるのでしょうか?
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
で実行できます。しかし、その改善を行うと、質問をする理由全体が破壊されるため、ここではそのままにしておきます。writeChan
if
atomically
enterShop