如何阻止直到 (1) 按键或 (2) 之前输入的一天中的时间(以较早者为准)hh:mm
格式已达到。我正在使用 Windows,以防万一。这DOS汇编程序 http://www.robvanderwoude.com/downloads/batchman.zip(它也可以在Windows上运行)通过类似的东西做我想要的batchman waittil 16:30
从 Windows 控制台,但我想完全在 Haskell 中完成,(即without使用该程序)。
可以启动两个线程:一个读取字符,另一个等待指定时间;他们都写一个MVar http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Concurrent-MVar.html发出完成信号。
这有点棘手,但主要是由于细节:我们想要stdin
在无缓冲和无回显模式下,单击一次按键即可停止等待而不打印任何内容,然后恢复原始状态;并且我们还需要在任一线程完成后终止两个线程,这样我们就可以停止读取stdin
一旦超时到期。此外,如果发生异常,我们需要确保正确清理。bracket http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Exception.html#v:bracket简化了这里的清理逻辑,但它仍然很丑陋:
import Prelude hiding (catch)
import Control.Exception
import Control.Concurrent
import System.IO
withRawStdin :: IO a -> IO a
withRawStdin = bracket uncook restore . const
where
uncook = do
oldBuffering <- hGetBuffering stdin
oldEcho <- hGetEcho stdin
hSetBuffering stdin NoBuffering
hSetEcho stdin False
return (oldBuffering, oldEcho)
restore (oldBuffering, oldEcho) = do
hSetBuffering stdin oldBuffering
hSetEcho stdin oldEcho
waitFor :: Int -> IO ()
waitFor delay = do
done <- newEmptyMVar
withRawStdin . bracket (start done) cleanUp $ \_ -> takeMVar done
where
start done = do
t1 <- forkIO $ getChar >> putMVar done ()
t2 <- forkIO $ threadDelay delay >> putMVar done ()
return (t1, t2)
cleanUp (t1, t2) = do
killThread t1
killThread t2
即使在这之后,这个解决方案仍然无法处理等待直到特定时间的问题——只是等待一定数量的微秒。为了将一天中的某个时间转化为几微秒的睡眠时间,之前的这个问题 https://stackoverflow.com/questions/8575118/sleeping-until-the-start-of-the-next-minute可能有帮助。如果睡眠时间足够长,那么它们可能不适合Int
微秒,所以你可能必须使用threadDelay
在一个循环中,或者delay http://hackage.haskell.org/packages/archive/unbounded-delays/latest/doc/html/Control-Concurrent-Thread-Delay.html来自无限延迟 http://hackage.haskell.org/package/unbounded-delays包裹。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)