即使没有`print'的东西,循环线程也不会挂起`hFlush stdout` [英] Loop thread hangs without `hFlush stdout` even there are no `print` things

查看:167
本文介绍了即使没有`print'的东西,循环线程也不会挂起`hFlush stdout`的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我测试一些关于线程代码的简单案例时,我发现了一些循环挂起而没有 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆