Haskell FFI : Foreignptr은 해방되지 않는 것 같습니다 (아마도 GHC 버그일까요?)
-
06-07-2019 - |
문제
다음 코드 스 니펫을 고려하십시오
import qualified Foreign.Concurrent
import Foreign.Ptr (nullPtr)
main :: IO ()
main = do
putStrLn "start"
a <- Foreign.Concurrent.newForeignPtr nullPtr $
putStrLn "a was deleted"
putStrLn "end"
다음 출력을 생성합니다.
start
end
나는 볼 것이라고 기대했을 것이다 "a was deleted
"어딘가에 start
..
무슨 일이 일어나고 있는지 모르겠습니다. 몇 가지 추측이 있습니다.
- 프로그램이 완료되면 쓰레기 수집가가 나머지 물체를 수집하지 않습니다.
putStrLn
이후의 일을 중단합니다main
마무리. (BTW 나는 외국 수입과 같은 것을 시도했다puts
그리고 같은 결과를 얻었습니다)- 내 이해
ForeignPtr
부족합니다 - GHC 버그? (ENV : GHC 6.10.3, Intel Mac)
사용할 때 Foreign.ForeignPtr.newForeignPtr
대신에 Foreign.Concurrent.newForeignPtr
작동하는 것 같습니다.
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C.String (CString, newCString)
import Foreign.ForeignPtr (newForeignPtr)
import Foreign.Ptr (FunPtr)
foreign import ccall "&puts" puts :: FunPtr (CString -> IO ())
main :: IO ()
main = do
putStrLn "start"
message <- newCString "a was \"deleted\""
a <- newForeignPtr puts message
putStrLn "end"
출력 :
start
end
a was "deleted"
해결책
문서에서 forex.foreign.newforeignptr:
마지막 참조가 삭제 된 후 결승자가 얼마나 빨리 실행되는지에 대한 보장은 없습니다. 이것은 Haskell Storage Manager의 세부 사항에 따라 다릅니다. 실제로, 파이널 라이저가 전혀 실행된다는 보장은 없습니다. 프로그램은 최종화 업체로 종료 될 수 있습니다.
따라서 정의되지 않은 행동에 빠지게됩니다. 즉, 모든 일이 발생할 수 있으며 플랫폼에서 플랫폼으로 변경 될 수 있습니다 (Windows 아래에서 보았 듯이) 또는 릴리스 릴리스.
두 기능간에보고있는 행동 차이의 원인은 문서에 의해 암시 될 수 있습니다. 외국 .concurrent.newforeignptr:
이 최종화기는 반드시 별도의 스레드에서 실행됩니다 ...
외국의 외국 버전의 최종화기가 기본 스레드를 사용하지만 외국 스레드가 별도의 스레드를 사용하는 경우 다른 스레드가 작업을 완료하기를 기다리지 않고 기본 스레드가 종료 될 수 있습니다. 다른 스레드는 결승전을 실행하지 않습니다.
물론, 외국인의 문서는 주장하고,
유일한 보장은 프로그램이 종료되기 전에 최종화기가 실행된다는 것입니다.
파이널 제이저가 다른 스레드에서 실행 중이라면 작업을 수행하는 데 임의의 시간이 걸릴 수 있으므로 (영원히 차단), 따라서 메인 스레드는 절대 없기 때문에 실제로 이것을 주장해야할지 확신하지 못합니다. 프로그램이 종료되도록 강요 할 수 있습니다. 그것은 이것과 충돌 할 것입니다 Control.concurrent:
독립형 GHC 프로그램에서는 프로세스가 종료 되려면 주 스레드 만 종료해야합니다. 따라서 다른 모든 포크 스레드는 메인 스레드와 동시에 단순히 종료됩니다 (이러한 종류의 행동에 대한 용어는 "데모닉 스레드"입니다).