我在做一些實驗併發和內存的知名度和跑進這種奇怪的行爲(見註釋在線):叉狀IOREF閱讀器的功能似乎停滯主線程
module Main
where
import Data.IORef
import Control.Concurrent
import System.CPUTime
import System.IO
main = do
hSetBuffering stdout NoBuffering
r <- newIORef False
putStrLn "forking..." -- PRINTED
forkIO $ f r
threadDelay 1000000
putStrLn "writeIORef" -- NEVER PRINTED
writeIORef r True
threadDelay maxBound
f :: IORef Bool -> IO()
f r = readIORef r >>= \b-> if b then print "NEVER PRINTED" else f r
我期待也許writeIORef
不被對於子線程是可見的,但對於主線程來說並不簡單(顯然)失速。
編上GHC 7.8.3
cabal exec ghc -- --make -fforce-recomp -O2 -threaded visibility.hs
與
./visibility +RTS -N
跑這裏發生了什麼?
編輯:所以我的機器有兩個真正的核心和兩個超線程核心,所以+RTS -N
GHC看到4個能力。每加布裏埃爾·岡薩雷斯的回答我嘗試了以下,看看也許調度是把兩個線程都在同一個物理處理器上:
module Main
where
import Data.IORef
import Control.Concurrent
import GHC.Conc(threadCapability,myThreadId,forkOn)
main = do
r <- newIORef False
putStrLn "going..."
(cap,_) <- threadCapability =<< myThreadId
forkOn (cap+1) $ f r -- TRIED cap+1, +2, +3....
threadDelay 1000000
putStrLn "writeIORef" -- BUT THIS STILL NEVER RUNS
writeIORef r True
threadDelay maxBound
f :: IORef Bool -> IO()
f r = readIORef r >>= \b-> if b then print "A" else f r
正是。一個解決方案是使用「yield」來分割沒有分配或其他類似點的塊。因此,對於這個問題中的忙碌等待,我們會有'... else yield >> f r'。顯然,繁忙的循環首先是一個糟糕的主意。另一種方法是使用'MVar'和'takeMVar'來代替信號。 – 2014-09-01 03:07:22
對不起,也許我正在密集...爲什麼我需要分叉線程來控制回主線程,以便讓'putStrLn「writeIORef」'運行?我用'+ RTS -N'運行,用'-threaded'編譯;兩個線程不應該同時運行嗎? – jberryman 2014-09-01 12:45:16
請參閱我的編輯,以及 – jberryman 2014-09-01 14:47:33