تفاعل فوركيو / كيلثريد مع فوركبروسيس
-
21-12-2019 - |
سؤال
لقد كتبت الرمز أدناه ، ولاحظت ذلك killThread
كتل والخيط لا يزال مستمرا.يحدث هذا فقط إذا قمت بذلك في عملية الشوكة ، إذا قمت بإزالة عملية الشوكة ، فكل شيء يعمل كما هو متوقع.
كود
{-# 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
هذه ليست المشكلة المعتادة أنه لا يوجد تخصيص الذاكرة وبالتالي لا يتم تشغيل جدولة مؤشر ترابط غك.لقد تحققت من ذلك عن طريق تشغيل البرنامج مع +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
.
إذا لسبب ما كنت بحاجة إلى عملية منفصلة ، سيكون لديك لكشف يدويا الاستثناءات غير المتزامنة في عملية الطفل في غك 7.6.3.