同時実行性とメモリの可視性についていくつかの実験を行っていたところ、この奇妙な動作に遭遇しました (インラインのコメントを参照)。
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
ここで何が起こっているのですか?
編集: 私のマシンには 2 つの実際のコアと 2 つのハイパースレッディング コアがあるため、+RTS -N
GHC では 4 つの機能が認識されます。Gabriel Gonzalez の回答に従って、次のことを試して、スケジューラが両方のスレッドを同じ物理プロセッサに配置していないかどうかを確認しました。
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