Frage

Ich habe den folgenden Code geschrieben und festgestellt, dass killThread blockiert und der Thread geht weiter.Das passiert nur, wenn ich es im forkProcess mache, wenn ich den forkProcess entferne, funktioniert alles wie erwartet.

Codes

{-# LANGUAGE TupleSections #-}
module Main where

import Control.Concurrent
import Control.Monad
import System.Posix.Process

{-# NOINLINE primes #-}
primes :: [Integer]
primes = 2:[x | x <- [3..], all (not . flip isDivisorOf x) (takeWhile (< truncate (sqrt $ fromInteger x :: Double)) primes)]
  where x `isDivisorOf` y = y `rem` x == 0

evaluator :: Show a => [a] -> IO ()
evaluator xs = do
  putStrLn "[Evaluator] Started evaluator."
  forM_ xs $ \x -> putStrLn $ "[Evaluator] Got result: " ++ show x
  putStrLn "[Evaluator] Evaluator exited."

test :: IO ThreadId
test = forkIO (evaluator $ filter ((== 13) . flip rem (79 * 5 * 7 * 3 * 3 * 2 * 3)) primes) -- Just some computation that doesn't finsish too fast

main :: IO ()
main = do
  pid <- forkProcess $ do
    a <- test
    threadDelay $ 4000 * 1000
    putStrLn "Canceling ..."
    killThread a
    putStrLn "Canceled"
  void $ getProcessStatus True False pid

Ausgabe

$ ghc test.hs -O -fforce-recomp -threaded -eventlog -rtsopts # I also tried with -threaded
$ ./test +RTS -N2  # I also tried without -N
[Evaluator] Started evaluator.
[Evaluator] Got result: 13
[Evaluator] Got result: 149323
[Evaluator] Got result: 447943
[Evaluator] Got result: 597253
[Evaluator] Got result: 746563
[Evaluator] Got result: 1045183
Canceling ...
[Evaluator] Got result: 1194493
[Evaluator] Got result: 1642423
[Evaluator] Got result: 1791733
[Evaluator] Got result: 2090353
[Evaluator] Got result: 2687593
[Evaluator] Got result: 3135523
[Evaluator] Got result: 3284833
[Evaluator] Got result: 4777933
[Evaluator] Got result: 5375173
^C[Evaluator] Got result: 5524483
^C

Dies ist nicht das übliche Problem, dass keine Speicherzuweisung erfolgt und daher der Thread-Scheduler von GHC nicht ausgeführt wird.Ich habe das überprüft, indem ich das Programm ausgeführt habe mit +RTS -sstderr, was zeigt, dass der Garbage Collector sehr oft läuft.Ich betreibe das auf Linux 64bit.

War es hilfreich?

Lösung

Dieser Fehlerbericht stellt fest, dass forkProcess maskiert asynchrone Ausnahmen im untergeordneten Prozess, obwohl dies in der Dokumentation nicht angegeben ist.Das Verhalten sollte in 7.8.1 behoben werden, wenn es veröffentlicht wird.

Natürlich, wenn asynchrone Ausnahmen maskiert sind, die throw im Inneren des killThread wird auf unbestimmte Zeit blockiert.Wenn Sie einfach die Zeilen in löschen main hast forkProcess und getProcessStatus, das Programm funktioniert wie vorgesehen:

module Main where

import           Control.Concurrent
import           Control.Monad
import           System.Posix.Process

{-# NOINLINE primes #-}
primes :: [Integer]
primes = 2:[ x | x <- [3..], all (not . flip isDivisorOf x) (takeWhile (< truncate (sqrt $ fromInteger x :: Double)) primes)]
  where x `isDivisorOf` y = y `rem` x == 0

evaluator :: Show a => [a] -> IO ()
evaluator = mapM_ $ \x ->
  putStrLn $ "[Evaluator] Got result: " ++ show x

test :: IO ThreadId
test = forkIO (evaluator $ filter ((== 13) . flip rem (79 * 5 * 7 * 3 * 3 * 2 * 3)) primes) -- Just some computation that doesn't finsish too fast

main :: IO ()
main = do
  a <- test
  threadDelay $ 4000 * 1000
  putStrLn "Canceling ..."
  killThread a
  putStrLn "Canceled"

Ich baue es mit ghc --make -threaded async.hs und renne mit ./async +RTS -N4.

Wenn Sie aus irgendeinem Grund einen separaten Prozess benötigen, müssen Sie asynchrone Ausnahmen im untergeordneten Prozess in GHC 7.6.3 manuell demaskieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top