2013-06-05 3 views
8

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を使うことができます。しかし、その改善を行うことは、質問をするための全理由を破壊するので、私はここにそのまま残しておきます。

答えて

11

TChan他のSTM操作と同様に、トランザクションがコミットされたときに操作が実行されるため、トランザクションが何回再試行されても、常に1回の書き込みで終了します。そうでなければ役に立たないだろう。自分を納得させるために

、この例を試してみてください。

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!"を出力します。その例外をスローする前に

+0

すばらしい例、感謝! –

+2

実際、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

関連する問題