簡體   English   中英

Haskell FFI:ForeignPtr似乎沒有被釋放(也許是GHC錯誤?)

[英]Haskell FFI: ForeignPtr seems not to get freed (maybe a GHC bug?)

考慮以下代碼片段

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

我本來希望在start后某處看到“ a was deleted ”。

我不知道這是怎么回事。 我有一些猜測:

  • 程序完成時,垃圾收集器不會收集剩余的對象
  • main完成后, putStrLn停止工作。 (順便說一句,我用國外進口的puts嘗試了同樣的事情,並得到了相同的結果)
  • 我對ForeignPtr了解不足
  • GHC錯誤? (環境: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"

Foreign.Foreign.newForeignPtr的文檔中:

請注意,不能保證在刪除最后一個引用后多長時間執行終結器; 這取決於Haskell存儲管理器的詳細信息。 的確,根本不能保證終結器會被執行。 程序可能會以終結器未完成而退出。

因此,您遇到了不確定的行為:即,任何事情都可能發生,並且它可能因平台而異(如我們在Windows下看到的那樣)或發行版本之間的變化。

Foreign.Concurrent.newForeignPtr的文檔可能暗示了您在兩個函數之間看到的行為差異的原因:

這些終結器必須在單獨的線程中運行...

如果該函數的Foreign.Foreign版本的終結器使用主線程,而Foreign.Concurrent的終結器使用單獨的線程,則很可能主線程關閉而無需等待其他線程完成其工作,因此其他線程永遠無法運行最終化。

當然,Foreign.Concurrent版本的文檔確實聲稱,

唯一的保證是終結器在程序終止之前運行。

我不確定他們是否真的應該聲稱這一點,因為如果終結器在其他線程中運行,則他們可能需要花費任意時間來完成工作(甚至永遠阻塞),因此主線程永遠不會能夠強制程序退出。 這將與Control.Concurrent的沖突:

在獨立的GHC程序中,只需要終止主線程即可終止進程。 因此,所有其他派生線程將僅在與主線程的同時終止(這種行為的術語是“守護線程”)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM