[英]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
了解不足 當使用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.