了解并行和并发Haskell中的日志记录示例

时间:2017-10-22 20:44:58

标签: haskell

Parallel and Concurrent Haskell的MVar记录示例中,它显示以下内容:

import Control.Concurrent
import Control.Concurrent.MVar

data Logger = Logger (MVar LogCommand)

data LogCommand = Message String | Stop (MVar ())

initLogger :: IO Logger
initLogger = do
  m <- newEmptyMVar
  let l = Logger m
  forkIO (logger l)
  return l

logger :: Logger -> IO ()
logger (Logger m) = loop
  where 
   loop = do
    cmd <- takeMVar m
    case cmd of 
      Message msg -> putStrLn msg >> loop
      Stop s -> do
        putStrLn "logger: stop"
        putMVar s ()

logMessage :: Logger -> String -> IO ()
logMessage (Logger m) s = putMVar m (Message s)

logStop :: Logger -> IO ()
logStop (Logger m) = do
  s <- newEmptyMVar
  putMVar m (Stop s)
  takeMVar s

如果logger的最后一行,即putMVar s ()被删除,会丢失什么?

1 个答案:

答案 0 :(得分:4)

如果没有putMVar s (),调用logStop会在takeMVar s中挂起,因为其他任何内容都无法填充s。最终会抛出BlockedIndefinitelyOnMVar异常,杀死挂起的线程。

s存在有序关闭。它保证在logStop返回时,日志处理线程实际上已停止。

请参阅您链接的页面中的此文字:

  

[...] {...}}导致日志记录服务终止。后一个操作很重要,因为如果我们要关闭程序,我们需要确保日志服务已经完成处理任何未完成的请求。回想一下“A Simple Example: Reminders”当主线程退出时,程序立即终止,而不是等待其他线程先终止。因此logStop有一个额外的要求:在日志记录服务处理完所有未完成的请求并停止之前,它不得返回。

[...]

  

发送命令后,我们在新logStop上调用takeMVar以等待响应。在日志记录线程处理了MVar命令后,它将Stop放入此(),这允许MVar继续并takeMVar返回。