TChan是否已将其集成到Haskell STM中?

Dax*_*ohl 8 haskell stm

如果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 
Run Code Online (Sandbox Code Playgroud)

更新 我直到事实上hairRequestChan无论如何不必成为交易的一部分之后我才注意到.我可以使用常规的Chan和做writeChanif声明atomically方框enterShop.但是,做出这样的改进会破坏提出这个问题的全部理由,所以我会把它留在这里.

val*_*man 11

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
Run Code Online (Sandbox Code Playgroud)

这将抛出一个异常,抱怨该事务被无限期阻止.如果writeTChan在事务提交之前导致写入,程序将打印"hi!" 在抛出那个例外之前.

  • 实际上,TChans是使用TVars在纯Haskell中实现的([这里](http://hackage.haskell.org/packages/archive/stm/2.1.2.2/doc/html/src/Control-Concurrent-STM-TChan.html )是TChan模块的源,因此它们获得与TVars相同的隔离量. (2认同)