Simon Marlow给了High performance concurrency在 Haskell eXchange 2012 上发表演讲。由于时间限制,他跳过了关于简单并发聊天服务器的部分。对省略的内容感到好奇,通过网络搜索发现了类似的 slides on server applications和 implementation 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
andfinally
(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
最佳答案
您要确保每一个成功的 checkAddClient
与 removeClient
配对. finally
底部的声明仅保证 removeClient
如果 runClient
则运行行动开始。
但是,checkAddClient
结尾之间有一个短暂的窗口。和 runClient
的开头该代码可能会收到异步异常。如果是,finally
没有机会注册 removeClient
命令。这就是西蒙所说的同步破解。
解决方案是默认屏蔽异步异常,只允许它们出现在某些地方(即由 restore
包装的操作)。这封住了上述裂缝。
关于multithreading - 这个 Haskell 聊天代码中的同步缺陷是什么,修复方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14541910/