更新MVar会引发异常

时间:2017-10-16 11:54:11

标签: haskell

假设:

λ: >let x = Control.Concurrent.MVar.newMVar ""
λ: >:t x
x :: IO (MVar [Char])

我试图致电putMVar

λ: >:t putMVar
putMVar :: MVar a -> a -> IO ()

λ: >:t x
x :: IO (MVar [Char])

但它失败了

λ: >x >>= \y -> putMVar y "foo"
:^?^?

*** Exception: thread blocked indefinitely in an MVar operation

为什么会失败?如何使用x而不是"foo"更新""

2 个答案:

答案 0 :(得分:6)

让我们查看文档:

data MVar a
     

MVar(发音为“em-var”)是一个同步变量,用于   并发线程之间的通信。它可以被认为是一个   框,可能是空的或满的。

newMVar :: a -> IO (MVar a)
     

创建一个包含所提供值的MVar。

putMVar :: MVar a -> a -> IO ()
     

将值放入MVar。如果MVar当前已满,putMVar将会   等到它变空。

     

putMVar还有两个重要的属性:

     

putMVar是单唤醒。也就是说,如果有多个线程   在putMVar中被阻塞,并且MVar变空,只有一个线程会   被唤醒运行时保证唤醒线程完成   它的putMVar操作。当一个MVar阻塞多个线程时,   它们以FIFO顺序被唤醒。这对于提供公平性很有用   使用MVars构建的抽象属性。

melpomene的答案包含正确的解释。我让我的答案留在这里引用文献。

答案 1 :(得分:6)

x不是MVar。这是一个创建MVar的操作,即newMVar ""的另一个名称。

x >>= \y -> putMVar y "foo"是一项创建MVar并将其命名为y的操作。然后,它会尝试将"foo"放入MVar。但是,y已包含"",因此putMVar会阻止。它不会永远阻止,因为y是此操作中的局部变量,这意味着没有其他人可以访问它并且不存在任何读者。 putMVar检测到这种情况(死锁)并引发异常。

你应该做的是从以下开始:

x <- newMVar ""

这使x成为MVar

然后你可以拿出旧值(""):

takeMVar x

并在

中添加新值
putMVar x "foo"

MVar不支持在一个步骤中替换现有值;首先必须将其取出,然后输入新值。)