문제

아래 코드를 작성했는데, killThread 블록이 있어도 스레드는 계속됩니다.이는 forkProcess에서 수행할 경우에만 발생하며, forkProcess를 제거하면 모든 것이 예상대로 작동합니다.

암호

{-# 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

산출

$ 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

이는 메모리 할당이 없어 GHC의 스레드 스케줄러가 실행되지 않는 일반적인 문제가 아닙니다.나는 프로그램을 실행하여 그것을 확인했습니다. +RTS -sstderr, 이는 가비지 수집기가 매우 자주 실행되고 있음을 나타냅니다.저는 이것을 리눅스 64비트에서 실행하고 있습니다.

도움이 되었습니까?

해결책

이것 버그 보고서 메모 forkProcess 문서에 그러한 내용이 표시되어 있지 않음에도 불구하고 하위 프로세스의 비동기 예외를 마스크합니다.이 동작은 릴리스되면 7.8.1에서 수정되어야 합니다.

물론, 비동기 예외가 마스크되면 throw 안에 killThread 무기한 차단됩니다.단순히 줄을 삭제하면 main 포함하는 forkProcess 그리고 getProcessStatus, 프로그램은 의도한 대로 작동합니다.

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"

나는 그것을 구축 ghc --make -threaded async.hs 그리고 함께 실행 ./async +RTS -N4.

어떤 이유로 별도의 프로세스가 필요한 경우 GHC 7.6.3의 하위 프로세스에서 비동기 예외를 수동으로 마스크 해제해야 합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top