线程应用程序中的 unsafePerformIO 不起作用 [英] unsafePerformIO in threaded applications does not work

查看:67
本文介绍了线程应用程序中的 unsafePerformIO 不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是示例程序的源代码:

Below is the source of a sample program:

当我从 ghci 运行它时,printJob 和 printJob2 都运行良好,并将十行写入文本文件.

When I run it from ghci both printJob and printJob2 run fine and write ten lines into a text file.

但是当用 -threaded 标志编译时,程序只写一行.

But when compiled with -threaded flag, the program writes only one line.

我在 ArchLinux 上安装了 ghc 7.0.3

I have ghc 7.0.3 on ArchLinux

这是编译命令:

ghc -threaded -Wall -O2 -rtsopts -with-rtsopts=-N -o testmvar testmvar.hs

我做错了什么?为什么它在线程模式下不起作用?

What am I am doing wrong ? Why it does not work in threaded mode ?

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))

hammar 指出,如果主应用程序比所有生成的线程早退出,那么它们将被杀死并建议在主应用程序结束时添加延迟.我做到了,正如他预测的那样,它奏效了.

hammar pointed out that if main application exits earlier than all spawned threads, then they will be killed and suggested to add a delay at the end of main. I did and as he predicted, it works.

推荐答案

问题是你的主线程结束得太快了,当一个 Haskell 程序的主线程结束时,所有其他线程都会被自动杀死.根据线程的调度方式,这可能会在任何线程有机会运行之前发生.

The problem is that your main thread finishes too soon, and when the main thread of a Haskell program finishes, all other threads get killed automatically. Depending on how the threads get scheduled, this might happen before any of the threads have had a chance to run at all.

一个快速而肮脏的解决方案是简单地在 main 的末尾添加一个 threadDelay,尽管更健壮的方法是使用像 这样的同步原语>MVar 在主线程可以完成时发出信号.

A quick and dirty solution is to simply add a threadDelay at the end of main, though a more robust method would be to use a synchronization primitive like an MVar to signal when it's OK for the main thread to finish.

例如:

main = do
  vars <- forM [1..10] $ \x -> do
    done <- newEmptyMVar -- Each thread gets an MVar to signal when it's done
    forkIO $ printJob (show x) >> putMVar done ()
    return done

  -- Wait for all threads to finish before exiting
  mapM_ takeMVar vars

这篇关于线程应用程序中的 unsafePerformIO 不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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