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
.
正如您在评论中所说,如果没有并发,您就可以编写类似的内容
modifyAndReturn ref f = do
old <- readIORef ref
let !(new, r) = f old
writeIORef r new
return r
Run Code Online (Sandbox Code Playgroud)
但在并发上下文中,其他人可以更改读取和写入之间的引用。