10

IORef如果我在多个线程之间共享一个,并使用atomicModifyIORef它来写入:

atomicModifyIORef ref (\_ -> (new, ()))

用普通的 old 读取值是否安全readIORef?或者修改后是否有机会readIORef在另一个线程中返回旧值atomicModifyIORef

我认为这就是文档所暗示的:

atomicModifyIORef 充当重新排序的障碍。多个 atomicModifyIORef 操作以严格的程序顺序发生。永远不会观察到 atomicModifyIORef 发生在任何更早(按程序顺序)的 IORef 操作之前,或在任何以后的 IORef 操作之后。

我只是想确定一下。

4

3 回答 3

14

atomicModifyIORef保证原子读取和随后的原子写入之间不会发生任何事情,从而使整个操作成为原子操作。您引用的评论只是指出不会atomicModifyIORef并行发生,并且优化器不会尝试重新排序语句以优化程序(在某些情况下可以安全地移动单独的读取和写入;例如a' <- read a; b' <- read b; write c $ a' + b',读取可以安全地重新排序)

readIORef已经是原子的,因为它只执行一个操作。

但是,您正在讨论一个不同的问题。是的,如果atomicModify发生在t=3msread发生在t=4ms,您将获得修改后的值。然而; 线程不能保证并行运行,所以如果你这样做(伪代码):

forkIO $ do
  sleep 100 ms
  atomicModify
sleep 1000 ms
read

...不能保证在修改后会发生读取(不过,在现代操作系统上极不可能发生),因为操作系统可能会决定以一种不会发生的方式安排新的短期线程平行线。

于 2012-02-17T12:27:15.830 回答
2

如果你想在多个线程之间共享一个可变引用,你真的应该TVar使用IORef. 毕竟,这就是 TVar 的全部动机。您使用 TVar 的方式与 IORef 几乎相同,但任何访问或修改都需要包含在一个atomically始终保证是原子操作的块内。

于 2012-02-17T13:02:28.120 回答
2

您不想将 IORef 与多个线程一起使用,因为它们基本上不提供任何保证。我通常使用 MVar 代替。

于 2012-02-17T13:10:11.007 回答