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

Gre*_*con 7 concurrency multithreading haskell chat

Simon Marlow在Haskell eXchange 2012上发表了高性能并发演讲.由于时间限制,他跳过了一个简单的并发聊天服务器上的部分.对于省略的内容感到好奇,网络搜索在服务器应用程序上找到了类似的幻灯片,在GitHub上找到了一个实现.

幻灯片33读取

回去谈谈......

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
Run Code Online (Sandbox Code Playgroud)

严格地说,我们应该堵塞的孔checkAddClientfinally(见注释...)

早些时候,幻灯片3提到"笔记中的第14章",我认为这是他即将出版的书.什么是checkAddClient和之间的同步裂缝finally,以及我们如何插入它?

上述实现使用maskControl.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
Run Code Online (Sandbox Code Playgroud)

Gab*_*lez 2

您要确保每个成功的项目都checkAddClientremoveClient. finally底部的语句仅保证在操作开始removeClient时运行runClient

但是,在代码可以接收异步异常的结束checkAddClient和开始之间有一个短暂的窗口。runClient如果这样做,finally将没有机会注册该removeClient命令。这就是西蒙所说的同步裂缝。

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