下面是一个示例程序的源:unsafePerformIO在线程应用程序无法正常工作
当我从ghci中运行它都PRINTJOB和printJob2运行正常,写十行到一个文本文件中。
但是,当使用-threaded标志编译时,程序只写入一行。
我有ArchLinux的
以下是编译命令GHC 7.0.3:
ghc -threaded -Wall -O2 -rtsopts -with-rtsopts=-N -o testmvar testmvar.hs
什么我做错了吗?为什么它不能在线程模式下工作?
import Control.Concurrent.MVar
import Control.Concurrent (forkIO)
import Control.Exception (bracket)
import Control.Monad (forM_)
import System.IO.Unsafe (unsafePerformIO)
import System.IO (hPutStrLn, stderr)
{-# NOINLINE p #-}
p :: MVar Int
p = unsafePerformIO $ newMVar (1::Int)
{-# NOINLINE printJob #-}
printJob x = bracket (takeMVar p) (putMVar p . (+ 1))
(\a -> do
appendFile "mvarlog.txt" $ "Input: " ++ x ++ "; Counter: " ++ show a ++ "\n"
)
{-# NOINLINE printJob2 #-}
printJob2 = unsafePerformIO $ do
p2 <- newEmptyMVar
return $ (\x -> bracket (putMVar p2 True) (\_ -> takeMVar p2)
(\_ -> do
appendFile "mvarlog.txt" $ "preformed " ++ x ++ "\n"
))
main = do
forM_ [1..10]
(\x -> forkIO $ printJob (show x))
编辑:哈马尔指出,如果主应用程序退出早于所有产生的线程,那么他们将被杀死,并建议在主末尾添加的延迟。 我的确如他预测的那样工作。
我不确定这里发生了什么(编译可能会触发GHCi不存在的优化,并且这些优化消除了对'unsafePerformIO'的调用),但是我觉得值得再次说'顾名思义,unsafePerformIO'就是* unsafe *,如果你使用它,东西*将会中断。 (好吧,除非你非常非常小心,但可能也是如此。) – 2012-02-26 00:07:42
如果你在'main'的末尾添加延迟,你会得到相同的结果吗?一旦主线程完成,所有其他线程都会被终止,所以根据事情的计划方式,这可能什么都不做 - 独立于与'unsafePerformIO'相关的任何问题。 – hammar 2012-02-26 00:19:45
@hammar你是对的!我在main的最后添加了threadDelay,现在一切正常。谢谢!如果你把它作为一个单独的答案,我会接受它。 – 2012-02-26 00:26:58