1

以下はサンプルプログラムのソースです。

ghci から実行すると、printJob と printJob2 の両方が正常に実行され、10 行がテキスト ファイルに書き込まれます。

しかし、-threaded フラグを指定してコンパイルすると、プログラムは 1 行しか書き込みません。

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

編集: hammar は、メイン アプリケーションが生成されたすべてのスレッドよりも早く終了した場合、それらは強制終了され、メインの最後に遅延を追加するよう提案されることを指摘しました。私はそうしました、そして彼が予測したように、それはうまくいきます.

4

2 に答える 2

5

問題は、メイン スレッドの終了が早すぎることです。Haskell プログラムのメイン スレッドが終了すると、他のすべてのスレッドが自動的に強制終了されます。スレッドのスケジュール方法によっては、スレッドがまったく実行される前に、これが発生する可能性があります。

手っ取り早い解決策は、単にthreadDelayの最後に を追加するmainことですが、より堅牢な方法は、 のような同期プリミティブを使用しMVarて、メイン スレッドが終了しても問題がないことを知らせることです。

例えば:

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
于 2012-02-26T00:46:55.150 に答える
0

もちろん、うまくいきません。unsafePerformIO を使用すると、常に悩まされます。使用しないようにコードを構成します。それを使用してグローバル変数を作成することは、正当な使用法ではありません。それがリーダーモナドの目的です。Haskell では unsafePerformIO は必要ありません。

明らかに壊れているこの「トリック」を人々が勧めると、私は死ぬ。盲人が盲人を導くようなものです。Haskell の使用に問題はありません。Haskell は、直面するすべての問題に対して本当に美しくエレガントなソリューションを備えていますが、学習する代わりにそれと戦うことに固執すると、常にバグに遭遇し続けることになります。

于 2012-02-26T22:53:42.583 に答える