haskell - 如何安全地中止 getChar?

标签 haskell io

我想选择性地中止 getChar行动。 我需要以下功能:

getChar' :: (Char -> IO ()) -> IO (IO ())

如果是abort <- getChar' callback ,从标准输入读取字符,除非 abort在角色可用之前调用。 如果读取一个字符,callback用它来调用。

我有以下原型(prototype)实现:

import Control.Monad
import Control.Concurrent

getChar' :: (Char -> IO ()) -> IO (IO ())
getChar' callback = do
    v <- newEmptyMVar
    tid <- forkIO $ do
        c <- getChar
        b <- tryPutMVar v ()
        when b $ callback c
    return $ do
        b <- tryPutMVar v ()
        when b $ killThread tid

问题是 killThread可能会在读取字符后但在放置 () 之前中止线程进入 MVar。

我不知道如何解决这个问题,基础包有可能吗? 如果没有,您是否在其他包中看到过类似的功能?

最佳答案

我认为实现此目的最简单的方法是执行您自己的缓冲。这是一个简单的原型(prototype)。它假设您在程序中只调用一次 launchIOThread 。它不处理 EOF 或其他 IO 异常,但这应该很容易。

import Control.Concurrent
import Control.Concurrent.STM
import Data.Maybe
import Control.Monad

type Buffer = TVar (Maybe Char)

launchIOThread :: IO Buffer
launchIOThread = do
  buf <- atomically $ newTVar Nothing
  _ <- forkIO $ ioThread buf
  return buf

ioThread :: Buffer -> IO ()
ioThread buf = loop where
  loop =
    join $ atomically $ do
      contents <- readTVar buf
      if isJust contents -- no-one has taken the character yet
        then retry -- relax
        else return $ do
          c <- getChar
          atomically $ writeTVar buf (Just c)
          loop

getChar' :: Buffer -> (Char -> IO ()) -> IO (IO ())
getChar' buf callback = do
  abortFlag <- atomically $ newTVar False

  _ <- forkIO $ doGetChar abortFlag

  return $ atomically $ writeTVar abortFlag True

  where
    doGetChar abortFlag = join $ atomically $ do
      mbC <- readTVar buf
      abort <- readTVar abortFlag
      case mbC of
        Just c ->
          do writeTVar buf Nothing; return $ callback c
        Nothing | abort -> return $ return ()
        _ -> retry

关于haskell - 如何安全地中止 getChar?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16769579/

相关文章:

c - 如何根据传感器读数动态打印字符串

java - 扫描仪在使用 next() 或 nextFoo() 后跳过 nextLine()?

haskell - 如何在没有堆栈的情况下运行 shake

c - 如何将字符串从 Haskell 传递给 C?

haskell - 并行 parMap 和策略

python - 用Python读取一些乱七八糟的文件

haskell - 在 Reactive Banana 中寻找 `flatten::Event [a] -> Event a`

haskell - 将列表中的项目替换为另一个列表中具有匹配构造函数的项目

php - "./file"和 "file"相对路径有什么区别

java - 标记文本文件中的数据