haskell - 帮助理解 Haskell 中的 MVar 示例

标签 haskell concurrency

我正在尝试理解 GHC latest docs 中的 MVar 示例-

data SkipChan a = SkipChan (MVar (a, [MVar ()])) (MVar ())

newSkipChan :: IO (SkipChan a)
newSkipChan = do
     sem <- newEmptyMVar
     main <- newMVar (undefined, [sem])
     return (SkipChan main sem)

putSkipChan :: SkipChan a -> a -> IO ()
putSkipChan (SkipChan main _) v = do
     (_, sems) <- takeMVar main
     putMVar main (v, [])
     mapM_ (sem -> putMVar sem ()) sems

getSkipChan :: SkipChan a -> IO a
getSkipChan (SkipChan main sem) = do
     takeMVar sem
     (v, sems) <- takeMVar main
     putMVar main (v, sem:sems)
     return v

dupSkipChan :: SkipChan a -> IO (SkipChan a)
dupSkipChan (SkipChan main _) = do
     sem <- newEmptyMVar
     (v, sems) <- takeMVar main
     putMVar main (v, sem:sems)
     return (SkipChan main sem)

我理解了程序的大部分内容,但有两个问题 -

  1. putSkipChan 这样的操作是原子操作吗?似乎可以通过首先执行 takeMVar 来避免阻塞 putMVar。但是,如果有其他东西在 takeMVar 之后但在 putMVar 之前调用 putMVar,那不会失败吗?在这种情况下,程序似乎会永远阻塞。
  2. 为什么 dupSkipChansem 附加到 SkipChan 中的信号量列表中?这不是由 getSkipChan 完成的吗?在我看来,调用 dupSkipChan 后跟 getSkipChan (这似乎是你必须做的事情来拥有多个读者)会导致阻塞当 putSkipChan 尝试两次唤醒同一个信号量时?

最佳答案

  1. 您是对的,另一个线程可能会调用 putMVar main 并搞乱 putSkipChan。但创建上述代码的模块不会导出 SkipChan 构造函数,因此这种流氓操作是不可能的。

  2. dupSkipChan 创建一个名为 sem emptyMVar 并将其添加到 main 中的列表中。它不会添加在 newSkipChan 中创建的已有的。因此没有阻塞。

向此问题和评论的其他读者解释更多内容:这个想法是可能有多个读者线程。最初,SkipChan main sem1 是唯一的此类读取器。 dupSkipChan 生成一个 SkipChan main sem2。如果有数千名读者,那么您不希望向所有读者通知 putSkipChan 中的新值,因此设计是 getSkipChan 将其 sem 放入列表中主要的。按照 newSkipChandupSkipChan 中的方式初始化 SkipChan 还包括将新的空 sem 放入 main 的列表中。

上述初始化和设计意味着第一个getSkipChan获取最近已写入的过去值(或第一个到达的值的 block )。该 SkipChan 上的 future getSkipChan 将始终获得比之前获得的值更新的值,并且如果该值已经可用,则这些值不会阻塞。

关于haskell - 帮助理解 Haskell 中的 MVar 示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7256860/

相关文章:

multithreading - CountDownLatch 中 await() 的目的是什么?

java - 我应该使用什么作为集合的内存屏障?

haskell - 如何创建有限版本的 IO monad

Haskell 字符串操作

haskell - 为什么 httpJSON 失败,但 httpLBS 成功?

haskell - 在 Haskell 中证明一个相当简单的定理

list - Haskell:调用其他函数+递归

postgresql - 为什么 PostgreSQL 中止这个可序列化的计划

java - 在这种情况下如何处理并发?

java - 遍历 List 时出现 ConcurrentModificationException