STMトランザクションが失敗して再試行する場合は、writeTChan
へのコールが再実行されるため、2つの書き込みが終了するか、トランザクションがコミットするとSTMは実際に書き込みを実行しますか? enterShop
のトランザクションが初めて失敗した場合、顧客は2つのヘアカットを取得する可能性がありますか?TChanの書き込みはHaskell STMに統合されていますか?
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
を使用し、if
の文の中での後にatomically
のブロックをenterShop
に入れて、writeChan
を使うことができます。しかし、その改善を行うことは、質問をするための全理由を破壊するので、私はここにそのまま残しておきます。
すばらしい例、感謝! –
実際、TChansは、TVars(ここではhttp://hackage.haskell.org/packages/archive/stm/2.1.2.2/doc/html/src/Control-Concurrent-STM-TChan)を使って純Haskellで実装されています。 html)はTChanモジュールのソースです)、TVarsに与えられたのと同じ量の分離を受け取ります。 – javawizard