multithreading - 这个 Haskell 聊天代码中的同步缺陷是什么,修复方法是什么?

标签 multithreading haskell concurrency chat

Simon Marlow给了High performance concurrency在 Haskell eXchange 2012 上发表演讲。由于时间限制,他跳过了关于简单并发聊天服务器的部分。对省略的内容感到好奇,通过网络搜索发现了类似的 slides on server applicationsimplementation on GitHub .

Slide 33

Back to talk…

talk :: Server -> Handle -> IO ()
talk server@Server{..} handle = do
    hSetNewlineMode handle universalNewlineMode
    hSetBuffering handle LineBuffering
    readName
  where
    readName = do
      hPutStrLn handle "What is your name?"
      name <- hGetLine handle
      m <- checkAddClient server name handle
      case m of
         Nothing -> do
           hPrintf handle "The name %s is in use" name
           readName
         Just client -> do
           runClient server client
              `finally` removeClient server name

Strictly speaking we should plug the hole between checkAddClient and finally (see the notes…)



早些时候,slide 3提到“注释中的第 14 章”,我假设是指他的 upcoming book . checkAddClient之间的同步破解是什么和 finally ,我们如何插入它?

上述实现使用 mask 来自 Control.Exception。如果这是解决方法,那么不合时宜的异常会破坏聚会的情况是什么?

...
readName = do
  hPutStrLn handle "What is your name?"
  name <- hGetLine handle
  if null name
     then readName
     else mask $ \restore -> do
            ok <- checkAddClient server name handle
            case ok of
              Nothing -> restore $ do
                 hPrintf handle
                    "The name %s is in use, please choose another\n" name
                 readName
              Just client ->
                 restore (runClient server client)
                   `finally` removeClient server name

最佳答案

您要确保每一个成功的 checkAddClientremoveClient 配对. finally底部的声明仅保证 removeClient如果 runClient 则运行行动开始。

但是,checkAddClient 结尾之间有一个短暂的窗口。和 runClient 的开头该代码可能会收到异步异常。如果是,finally没有机会注册 removeClient命令。这就是西蒙所说的同步破解。

解决方案是默认屏蔽异步异常,只允许它们出现在某些地方(即由 restore 包装的操作)。这封住了上述裂缝。

关于multithreading - 这个 Haskell 聊天代码中的同步缺陷是什么,修复方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14541910/

相关文章:

java - OutputStream 未转换为字符串变量

haskell - <$> 和 fmap 的区别

scala - Scala Actor 中的 Thread.sleep

java - 多个线程可以看到 Java 中直接映射的 ByteBuffer 上的写入吗?

multithreading - Parallel For-Each 与 Scatter Gather in mule

multithreading - 从 QRunnable 发出信号或发布事件

multithreading - 如何避免更新死锁

haskell - 为什么尾递归模数可以优化?

performance - 为什么不能应用遍历数组? (或者是吗?)

java - 在许 cocoa 用之前,Semaphore.tryAcquire(...) 会阻塞还是自旋?