即使没有`print'的东西,循环线程也不会挂起`hFlush stdout` [英] Loop thread hangs without `hFlush stdout` even there are no `print` things
问题描述
当我测试一些关于线程代码的简单案例时,我发现了一些循环挂起而没有 hFlush stdout
,甚至它不使用任何打印
东西。
import Control.Concurrent
import System.IO
import Data.IORef
delay :: Int - > IO()
delay = threadDelay。 (* 1000000)
等待sw =循环
其中
循环=执行
v < - readIORef sw
--hFlush stdout - 没有这个,如果v
然后返回()
else循环
监视sw = forkIO $循环
其中
循环=
$挂起
bv< - readIORef sw
print v
delay 1
loop
main = do
sw< - newIORef False
forkIO $
延迟4
writeIORef sw True
监视器sw
等待sw
--putStrLn结束
这段代码是否存在 monitor sw
和 putStrLnEnd
存在或不存在。
然而,在中取消注释
,它正常工作并结束。 hFlush stdout
等待
$ b
这也发生在使用 MVar
code>。
import Control.Concurrent
import Control.Concurrent.MVar
import System .IO
delay :: Int - > IO()
delay = threadDelay。 (* 1000000)
wait :: MVar Bool - > IO()
wait sw = loop
where循环= do
v< - readMVar sw
hFlush stdout - 没有这个,挂起
如果v
然后返回()
else循环
$ b $ main main :: IO()
main = do
sw < - newMVar False
forkIO $ do
delay 4
modifyMVar_ sw(\_ - > return True)
wait sw
这两个代码在以 runghc
运行时可以正常运行。 然而,以下代码在没有 hFlush stdout
的情况下不会被挂起。
import Control.Concurrent
import Control.Concurrent.MVar
import System.IO
delay :: Int - > IO()
delay = threadDelay。 (* 1000000)
wait :: MVar Bool - > IO()
等待sw =循环
其中循环=做
v< - readMVar sw
如果v
然后返回()
else循环
main :: IO()
main = do
sw< - newEmptyMVar
forkIO $ do
delay 4
putMVar sw True
wait sw
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TVar
import System.IO
delay :: Int - > IO()
delay = threadDelay。 (* 1000000)
wait :: TVar Bool - > IO()
等待sw =自动执行$ do
v< - readTVar sw
除非重试
main :: IO()
main = do
sw < - newTVarIO False
forkIO $ do
延迟4
原子化$ writeTVar sw True
wait sw
我知道有区别。但是我找不到为什么某些代码挂起。
是 stdout
与处理线程有关吗?
您能解释没有 hFlush stdout
?
其他:
1.我已经用GHC 7.10.2 {OS X,Windows}测试了这段代码。
很可能编译器将 wait
优化为非分配繁忙循环。运行系统只是没有机会中断它让子线程运行。您可以通过添加分配或收益的任何操作来修复,例如 hFlush
或 threadDelay
。您还可以使用 -fno-omit-yield
来编译代码。 https://ghc.haskell.org/trac/ghc/ticket/367 和 https://ghc.haskell.org/trac/ghc/ticket/10639
When I test some simple cases about threaded codes,
I found some loop hang without hFlush stdout
even it does not use any print
things.
import Control.Concurrent
import System.IO
import Data.IORef
delay :: Int -> IO ()
delay = threadDelay . (* 1000000)
wait sw = loop
where
loop = do
v <- readIORef sw
--hFlush stdout -- without this, hang
if v
then return()
else loop
monitor sw = forkIO $ loop
where
loop = do
v <- readIORef sw
print v
delay 1
loop
main = do
sw <- newIORef False
forkIO $ do
delay 4
writeIORef sw True
monitor sw
wait sw
--putStrLn "End"
This code hangs whether monitor sw
and putStrLn "End"
exist or not.
However, just uncomment hFlush stdout
in wait
, it works properly and ends.
This also happens with a code using MVar
.
import Control.Concurrent
import Control.Concurrent.MVar
import System.IO
delay :: Int -> IO ()
delay = threadDelay . (* 1000000)
wait :: MVar Bool -> IO ()
wait sw = loop
where loop = do
v <- readMVar sw
hFlush stdout -- without this, hangs
if v
then return ()
else loop
main :: IO ()
main = do
sw <- newMVar False
forkIO $ do
delay 4
modifyMVar_ sw (\_ -> return True)
wait sw
These two codes will run properly when running by runghc
.
However, the codes below are not hanging without hFlush stdout
.
import Control.Concurrent
import Control.Concurrent.MVar
import System.IO
delay :: Int -> IO ()
delay = threadDelay . (* 1000000)
wait :: MVar Bool -> IO ()
wait sw = loop
where loop = do
v <- readMVar sw
if v
then return ()
else loop
main :: IO ()
main = do
sw <- newEmptyMVar
forkIO $ do
delay 4
putMVar sw True
wait sw
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TVar
import System.IO
delay :: Int -> IO ()
delay = threadDelay . (* 1000000)
wait :: TVar Bool -> IO ()
wait sw = atomically $ do
v <- readTVar sw
unless v retry
main :: IO ()
main = do
sw <- newTVarIO False
forkIO $ do
delay 4
atomically $ writeTVar sw True
wait sw
I know that there are difference. But I couldn't find out why some codes hang.
Is stdout
is related with handling thread?
Could you explain why the loops are hanging or not without hFlush stdout
?
Additional:
1. I've tested this codes with GHC 7.10.2 {OS X, Windows}
Most likely the compiler optimized the wait
into non-allocating busy loop. Runtime system just doesn't have a chance to interrupt it to let the child thread to run. You can "fix" by adding any action that allocates or yields, e.g. hFlush
or threadDelay
. Also you can compile the code with -fno-omit-yields
.
See also: https://ghc.haskell.org/trac/ghc/ticket/367 and https://ghc.haskell.org/trac/ghc/ticket/10639
这篇关于即使没有`print'的东西,循环线程也不会挂起`hFlush stdout`的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!