stavo facendo alcuni esperimenti con la concorrenza e la memoria visibilità e sono imbattuto in questo strano comportamento (vedi commenti in linea):funzione di lettore Forked IOREF sembra stallo thread principale
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
mi aspettavo forse il writeIORef
non essere visibile al thread figlio, ma non per il thread principale a semplicemente (apparentemente) stallo.
compilato su GHC 7.8.3
cabal exec ghc -- --make -fforce-recomp -O2 -threaded visibility.hs
e correre con
./visibility +RTS -N
cosa sta succedendo qui?
EDIT: Così la mia macchina ha due nuclei reali e due core hyperthreading, quindi con +RTS -N
GHC vede 4 capacità. Per risposta di Gabriel Gonzalez Ho provato il seguente per vedere se magari lo scheduler stava mettendo entrambi i fili sullo stesso processore fisico:
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
Esattamente. Una soluzione è usare 'yield' per suddividere i blocchi senza allocazioni o altri punti di questo tipo. Quindi per l'attesa impegnata nella domanda avremmo '... else yield >> f r'. Ovviamente i loop occupati sono generalmente una cattiva idea, in primo luogo. Un'alternativa è usare 'MVar' e' takeMVar' per la segnalazione invece. –
Scusate, forse sono denso ... perché dovrei aver bisogno che il thread biforcuto restituisca il controllo al thread principale in modo che "putStrLn" writeIORef "' venga eseguito? Sto correndo con '+ RTS -N', compilato con' -threaded'; i due thread non dovrebbero essere eseguiti simultaneamente? – jberryman
Vedi anche la mia modifica, – jberryman