我发现在使用MVar和Weak的时候存在问题:即使MVar仍然可以从函数作用域中访问(并且主线程正在阻塞它),Weak认为它应该被终止。只有启用优化编译时,这种行为才会发生。
平台:64位Linux
已验证GHC版本:6.10.4、6.12.3、7.0.4、7.2.2、7.4.1
为什么会出现这种情况?如果我正确理解了
平台:64位Linux
已验证GHC版本:6.10.4、6.12.3、7.0.4、7.2.2、7.4.1
module Main (main) where
import Control.Concurrent
import Control.Monad (forever, forM_)
import Data.IORef
import System.Mem
import System.Mem.Weak
dispatchPendingCalls :: IORef [Weak (MVar ())] -> IO ()
dispatchPendingCalls ref = forever $ do
threadDelay 100000
pending <- atomicModifyIORef ref (\p -> ([], p))
forM_ pending (\weak -> do
maybeMVar <- deRefWeak weak
case maybeMVar of
Just mvar -> putMVar mvar ()
Nothing -> putStrLn "dispatchPendingCalls: weak mvar is Nothing")
call :: IORef [Weak (MVar ())] -> IO ()
call ref = do
mvar <- newEmptyMVar
weak <- mkWeakPtr mvar (Just (putStrLn "call: finalising weak"))
putStrLn "call: about to insert weak into list"
atomicModifyIORef ref (\p -> (weak : p, ()))
putStrLn "call: inserted weak into list"
performGC
takeMVar mvar
putStrLn "call: took from mvar"
main :: IO ()
main = do
pendingCalls <- newIORef []
_ <- forkIO (dispatchPendingCalls pendingCalls)
call pendingCalls
期望输出:
$ ghc --make WeakMvar.hs
$ ./WeakMvar
call: about to insert weak into list
call: inserted weak into list
call: took from mvar
$
实际输出:
$ ghc --make -O2 WeakMvar.hs
$ ./WeakMvar
call: about to insert weak into list
call: inserted weak into list
call: finalizing weak
dispatchPendingCalls: weak mvar is Nothing
(never exits)
为什么会出现这种情况?如果我正确理解了
System.Mem.Weak
文档,那么takeMVar mvar
行应该保持mvar的活动状态,从而使其弱指针有效。然而,弱指针却认为在调用takeMVar
返回之前,MVar已经变得不可访问。