haskell - `forkIO` 和 `putMVar` : what's going on under the hood?

标签 haskell concurrency mutable

我希望有人能帮助我理解为什么下面的代码会生成下面的输出。代码来自 Simon Marlow 书中的并发章节(链接如下)。

根据对各种功能的描述,我假设第二个 putMVar鉴于 (i) 两个 putMVar函数是同一线程的一部分,并且 (ii) 已经分配了一个值。显然情况并非如此。很高兴了解这里“幕后”发生的事情。

(注意:这本书使用 do 表示法,但我更喜欢 >>= 表示法,因为我认为它更直接 - 因此下面的代码版本。)

Link to book

import Control.Concurrent

main :: IO ()
main = newEmptyMVar >>=
       \m -> forkIO (putMVar m 'x' >>= \_ -> putMVar m 'y') >>=
             \_ -> takeMVar m >>=
                   print >>=
                   \_ -> takeMVar m >>=
                         print

上面代码的输出:
% ./mvar2
'x'
'y'

最佳答案

为了我自己,这里是 do 中的代码符号。

main :: IO ()
main = do
  m <- newEmptyMVar
  forkIO $ do
    putMVar m 'x'
    putMVar m 'y'
  x <- takeMVar m
  print x
  y <- takeMVar m
  print y

我们拥有的是一个后台线程和一个在一小块内存上同时运行的主线程,MVar调用m .
MVar语义是这样的:MVar可以是空的或满的。如果您想阅读 MVar它是空的,那么你必须等到它变满。如果您 readMVar那么您将简单地解析存储在完整 MVar 中的值你尽快做。如果您 takeMVar然后您将解析该值,然后在阅读后立即将其清空。

另一方面,当你 putMVar将新值放入 MVar如果 MVar是空的。如果它已满,那么您必须等到它变空。

由于在读取和写入端有等待,因此线程在 MVar 的空虚和满度上变得同步。 .

所以在这个例子中,我们可以想象许多可能的线性化故事来说明执行如何进行。幸运的是,它们都以相同的方式工作。让我们调用后台线程BG和主线程MN .
t = 1  :  MN makes a new, empty MVar called 'm'
t = 2  :  BG puts 'x' in 'm' making it full
t = 3  :  BG attempts to put 'y' in 'm', but since 'm' is full BG blocks
t = 4  :  MN attempts to read 'm' and succeeds as it is full
t = 5  :  BG now places 'y' into the newly empty 'm'
t = 6  :  BG dies
t = 6  :  MN prints the value it previously read
t = 7  :  MN attempts to read 'm' and succeeds as it is full
t = 8  :  MN prints the value it previously read
t = 9  :  MN dies

正如我们所见,BG阻止在 MVar 中添加更多值比什么MN可以阅读。这会产生您观察到的打印语义。

关于haskell - `forkIO` 和 `putMVar` : what's going on under the hood?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26856108/

相关文章:

java - 如何实现用于流式传输斐波那契数的 Spliterator?

java - 并发修改异常

haskell - 如何在 IO monad 中使用可变结构

haskell - 将仿函数命名为仿函数

php - 在 MYSQL 中使用 SELECT MAX(id) 而不是在 PHP 中使用 mysql_insert_id() 有多糟糕?

haskell - 当我在另一个函数的应用程序中应用带有参数 n-1(无括号)的函数时,为什么会出现无限递归?

javascript - 在循环中关联按钮和单击操作

f# - 使用 F# 对可变值进行模式匹配

haskell - 在 Haskell 中提升高阶函数

haskell - 如何通过隐藏 'state'更改以sig类型编写没有IO的haskell函数