我可以确保 Haskell 执行原子 IO 操作吗?

24

我在Haskell中有两个执行IO的线程。(它们仅打印)。类似以下内容:

thread1 :: IO ()
thread1 = putStrLn "One"

thread2 :: IO ()
thread2 = putStrLn "Two"

我目前得到的结果如下:

OnTwoe
OTnweo

如何确保每个线程原子地完成其IO操作?

1个回答

26

使用同步变量来确保对资源的原子访问。 一种简单的方法是使用 MVar:

main = do
   lock <- newMVar ()
   forkIO $ ... lock 
   forkIO $ ... lock

现在,为了不交错地执行IO操作,每个线程都会获取锁:

thread1 lock = do
      withMVar lock $ \_ -> putStrLn "foo"

thread2 lock = do
      withMVar lock $ \_ -> putStrLn "bar"
一个备选的设计方案是,有一个专门的工作线程来执行所有的putStrLn操作,你可以通过Chan发送消息以便打印输出。

4
作为一个练习:尝试使用事务内存来有序访问资源来编写此代码。 - Don Stewart
2
我会尝试一下! 同时,我更改为: withMVar lock $ (_ -> putStrLn "bar") - Toymakerii
1
我没有使用过这个设计,但你在最后提到的替代设计在我的几个项目中表现得相当不错。 - Jeremy List
如果Monad上下文不是在IO中怎么办?我正在使用monad-parallel包,它能够分叉不是IO的Monad。我无法为非IO Monad使用mVars。 - CMCDragonkai
@Toymakerii 是正确的。withMVar 的第二个参数应该是一个函数,而不仅仅是 putStrLn "..." - CMCDragonkai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接