haskell - Control.Concurrent.Chan readChan 中的理论死锁

标签 haskell ghc

浏览readChan的源代码发现以下实现和注释,从base版本4.6开始:

-- |Read the next value from the 'Chan'.
readChan :: Chan a -> IO a
readChan (Chan readVar _) = do
  modifyMVarMasked readVar $ \read_end -> do -- Note [modifyMVarMasked]
    (ChItem val new_read_end) <- readMVar read_end
        -- Use readMVar here, not takeMVar,
        -- else dupChan doesn't work
    return (new_read_end, val)

-- Note [modifyMVarMasked]
-- This prevents a theoretical deadlock if an asynchronous exception
-- happens during the readMVar while the MVar is empty.  In that case
-- the read_end MVar will be left empty, and subsequent readers will
-- deadlock.  Using modifyMVarMasked prevents this.  The deadlock can
-- be reproduced, but only by expanding readMVar and inserting an
-- artificial yield between its takeMVar and putMVar operations.

在基础版本4.6之前,使用modifyMVar而不是modifyMVarMasked。

我不明白这里解决了什么理论问题。最后一句指出,如果线程在组成 readMVar 的 takeMVar 和 putMVar 之间让步,就会出现问题。但是当 readMVar 在 mask_ 下执行时,异步异常如何阻止成功 take 后的 put 呢?

如果您能帮助理解这里的问题,我们将不胜感激。

最佳答案

让我们比较一下 modifyMVarmodifyMVarMasked 的源代码,因为代码从使用一个更改为使用另一个:

modifyMVar m io =
  mask $ \restore -> do
    a      <- takeMVar m
    (a',b) <- restore (io a) `onException` putMVar m a
    putMVar m a'
    return b

modifyMVarMasked m io =
  mask_ $ do
    a      <- takeMVar m
    (a',b) <- io a `onException` putMVar m a
    putMVar m a'
    return b

这里的关键是 modifyMVar 在执行第二个参数之前调用 restore,而 modifyMVarMasked 则不会。因此,正如您在问题中声称的那样,在旧版本代码的 mask_ 下,readMVar 没有被调用!相反,它是在 restore 下调用的,因此毕竟可以启用异步异常。

关于haskell - Control.Concurrent.Chan readChan 中的理论死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21742932/

相关文章:

haskell - 在 Haskell 中并发读写 IOArray

exception - 优化和错误调用测试之间的交互

haskell - 当什么都没有改变时,如何阻止 GHC 重新编译模块?

haskell - 函数不仅有类型 : They ARE Types. 和种类。和排序。帮助重振精神

有哪些值得学习和学习的 Haskell 项目?

haskell - 具有类约束类型的值实际上会在运行时成为函数吗?

haskell - 有没有更干净、优雅的 Haskell 方式来编写这个 LCM 函数?

haskell - GHC 可以为 monad 转换器派生 Functor 和 Applicative 实例吗?

function - 将 (Maybe a, b) 转换为 Maybe (a,b)

macos - Emacs Haskell 模式 - Speedbar 未更新