Haskell在Windows环境下并行运行双进程发生阻塞问题咨询
问题原因
- 核心逻辑错误:
act1执行时会先调用takeMVar拿走共享变量的访问权限,之后直接阻塞在等待用户输入的getCharNoBuffering调用上,此时MVar处于空状态,act2调用takeMVar时自然会一直阻塞,直到act1拿到输入把修改后的值塞回MVar才能继续执行。 - Windows平台GHC运行时限制:如果编译时没有加
-threaded参数,默认的单线程运行时无法实现真正的多线程并行,阻塞IO的线程会卡住整个程序的执行。
修复方案
- 调整
act1的执行顺序:先等待用户输入,拿到输入后再短暂持有MVar完成修改,等待输入期间不占用MVar,给act2留够访问权限。 - 编译时添加
-threaded参数,启用多线程运行时。 - 正确设置终端输入无缓冲,确保
getChar可以立刻拿到用户输入不需要等回车。
修正后代码
import Control.Concurrent (forkIO, MVar, newMVar, takeMVar, putMVar, threadDelay) import Control.Monad (forever, forM_) import System.IO (hSetBuffering, stdin, stdout, BufferMode(NoBuffering, LineBuffering), hFlush) -- 示例辅助函数实现,可替换为你自己的逻辑 newDot :: (Int, Int) -> Char -> (Int, Int) newDot (x,y) 'w' = (x, y+1) newDot (x,y) 's' = (x, y-1) newDot (x,y) 'a' = (x-1, y) newDot (x,y) 'd' = (x+1, y) newDot pos _ = pos position :: (Int, Int) -> (Int, Int) position = id getCharNoBuffering :: IO Char getCharNoBuffering = getChar main = do -- 初始化终端缓冲模式 hSetBuffering stdin NoBuffering hSetBuffering stdout LineBuffering r <- newMVar (4,4) forkIO (act1 r) act2 r where act1 r = forever $ do -- 先等待用户输入,拿到输入后再操作MVar c <- getCharNoBuffering dot <- takeMVar r putMVar r (newDot dot c) act2 r = do forM_ [1..20] $ \_ -> do dot <- takeMVar r print (position dot) putMVar r dot -- 主动刷新输出缓冲确保内容立刻打印 hFlush stdout -- 可选:加100ms延迟避免打印速度太快看不清 threadDelay 100000
内容的提问来源于stack exchange,提问作者monadicAutomaton
相关产品推荐
相关产品推荐

