You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell在Windows环境下并行运行双进程发生阻塞问题咨询

问题原因
  • 核心逻辑错误:act1 执行时会先调用takeMVar拿走共享变量的访问权限,之后直接阻塞在等待用户输入的getCharNoBuffering调用上,此时MVar处于空状态,act2调用takeMVar时自然会一直阻塞,直到act1拿到输入把修改后的值塞回MVar才能继续执行。
  • Windows平台GHC运行时限制:如果编译时没有加-threaded参数,默认的单线程运行时无法实现真正的多线程并行,阻塞IO的线程会卡住整个程序的执行。
修复方案
  1. 调整act1的执行顺序:先等待用户输入,拿到输入后再短暂持有MVar完成修改,等待输入期间不占用MVar,给act2留够访问权限。
  2. 编译时添加-threaded参数,启用多线程运行时。
  3. 正确设置终端输入无缓冲,确保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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 00:39:00