TChan写入是否集成到Haskell STM中?

TChan写入是否集成到Haskell STM中?,haskell,stm,Haskell,Stm,如果STM事务失败并重试,对writechan的调用是否会重新执行,从而导致两次写入,或者STM是否仅在事务提交时才实际执行写入?i、 例如,这种解决睡眠理发师问题的方法有效吗?或者,如果enterShop中的交易第一次失败,客户可能会理发两次 import Control.Monad import Control.Concurrent import Control.Concurrent.STM import System.Random import Text.Printf runBarber

如果STM事务失败并重试,对
writechan
的调用是否会重新执行,从而导致两次写入,或者STM是否仅在事务提交时才实际执行写入?i、 例如,这种解决睡眠理发师问题的方法有效吗?或者,如果
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 
import-Control.Monad
导入控制。并发
导入控制.Concurrent.STM
导入系统。随机
导入文本.Printf
runBarber::TChan Int->TVar Int->IO()
runBarber HairutRequestChan seatsLeftVar=永远$do
customerId IO()
enterShop hairutrequestchan seatslefvar customerId=do
putStrLn$printf“%d进入店铺”客户ID

hasEmptySeat
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
导入控制。并发
导入控制.Concurrent.STM
导入控制.Concurrent.STM.TChan
main=do
ch>=putStrLn
作家
读卡器=原子。雷德尚
writer ch=atomically$writeTChan ch“嗨!”>>重试

这将引发一个异常,抱怨事务被无限期阻止。如果
writechan
在提交事务之前导致写入,程序将在抛出该异常之前打印“hi!”。

事实上,TChan是使用TVars(TChan模块的源代码)在纯Haskell中实现的,因此它们收到的隔离程度与TVars相同。