atomicModifyIORef的额外结果参数的目的是什么?

lef*_*out 9 concurrency haskell global-state ioref

签名modifyIORef很简单:

modifyIORef :: IORef a -> (a -> a) -> IO ()
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不是线程安全的.有一个替代方案可以解决这个问题:

atomicModifyIORef :: IORef a -> (a -> (a,b)) -> IO b
Run Code Online (Sandbox Code Playgroud)

这两个功能之间到底有什么区别?b在修改IORef可能从另一个线程读取的参数时,我应该如何使用该参数?

red*_*neb 12

额外参数用于提供返回值.例如,您可能希望能够原子地替换存储在a中的值IORef并返回旧值.你可以这样做:

atomicModifyIORef ref (\old -> (new, old))
Run Code Online (Sandbox Code Playgroud)

如果您没有要返回的值,则可以使用以下内容:

atomicModifyIORef_ :: IORef a -> (a -> a) -> IO ()
atomicModifyIORef_ ref f =
    atomicModifyIORef ref (\val -> (f val, ()))
Run Code Online (Sandbox Code Playgroud)

它具有相同的签名modifyIORef.


dfe*_*uer 2

正如您在评论中所说,如果没有并发,您就可以编写类似的内容

modifyAndReturn ref f = do
  old <- readIORef ref
  let !(new, r) = f old
  writeIORef r new
  return r
Run Code Online (Sandbox Code Playgroud)

但在并发上下文中,其他人可以更改读取和写入之间的引用。