diff options
author | David Feuer <David.Feuer@gmail.com> | 2023-02-27 21:52:23 -0500 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2023-03-26 15:33:02 -0400 |
commit | 4f93de888fb8be5241b476442045eb40b2a5abbd (patch) | |
tree | 19dbc7acfceb096287c753667c2ea10af9c8e8cd | |
parent | 656d4cb3e3a450ececcc72ffd2aca6f8e6489102 (diff) | |
download | haskell-4f93de888fb8be5241b476442045eb40b2a5abbd.tar.gz |
Update and expand atomic modification Haddocks
* The documentation for `atomicModifyIORef` and `atomicModifyIORef'`
were incomplete, and the documentation for `atomicModifyIORef` was
out of date. Update and expand.
* Remove a useless lazy pattern match in the definition of
`atomicModifyIORef`. The pair it claims to match lazily
was already forced by `atomicModifyIORef2`.
-rw-r--r-- | libraries/base/Data/IORef.hs | 42 | ||||
-rw-r--r-- | libraries/base/GHC/IORef.hs | 39 |
2 files changed, 67 insertions, 14 deletions
diff --git a/libraries/base/Data/IORef.hs b/libraries/base/Data/IORef.hs index 7cc8b3383b..f906ffd966 100644 --- a/libraries/base/Data/IORef.hs +++ b/libraries/base/Data/IORef.hs @@ -85,21 +85,45 @@ modifyIORef' ref f = do -- is recommended that if you need to do anything more complicated -- then using 'Control.Concurrent.MVar.MVar' instead is a good idea. -- --- 'atomicModifyIORef' does not apply the function strictly. This is important --- to know even if all you are doing is replacing the value. For example, this --- will leak memory: +-- Conceptually, -- --- >ref <- newIORef '1' --- >forever $ atomicModifyIORef ref (\_ -> ('2', ())) +-- @ +-- atomicModifyIORef ref f = do +-- -- Begin atomic block +-- old <- 'readIORef' ref +-- let r = f old +-- new = fst r +-- 'writeIORef' ref new +-- -- End atomic block +-- case r of +-- (_new, res) -> pure res +-- @ -- --- Use 'atomicModifyIORef'' or 'atomicWriteIORef' to avoid this problem. +-- The actions in the section labeled \"atomic block\" are not subject to +-- interference from other threads. In particular, it is impossible for the +-- value in the 'IORef' to change between the 'readIORef' and 'writeIORef' +-- invocations. -- --- This function imposes a memory barrier, preventing reordering; --- see "Data.IORef#memmodel" for details. +-- The user-supplied function is applied to the value stored in the 'IORef', +-- yielding a new value to store in the 'IORef' and a value to return. After +-- the new value is (lazily) stored in the 'IORef', @atomicModifyIORef@ forces +-- the result pair, but does not force either component of the result. To force +-- /both/ components, use 'atomicModifyIORef''. +-- +-- Note that +-- +-- @atomicModifyIORef ref (\_ -> undefined)@ +-- +-- will raise an exception in the calling thread, but will /also/ +-- install the bottoming value in the 'IORef', where it may be read by +-- other threads. +-- +-- This function imposes a memory barrier, preventing reordering around the +-- \"atomic block\"; see "Data.IORef#memmodel" for details. -- atomicModifyIORef :: IORef a -> (a -> (a,b)) -> IO b atomicModifyIORef ref f = do - (_old, ~(_new, res)) <- atomicModifyIORef2 ref f + (_old, (_new, res)) <- atomicModifyIORef2 ref f pure res -- | Variant of 'writeIORef'. The prefix "atomic" relates to a fact that diff --git a/libraries/base/GHC/IORef.hs b/libraries/base/GHC/IORef.hs index b1ce335225..f451746dcb 100644 --- a/libraries/base/GHC/IORef.hs +++ b/libraries/base/GHC/IORef.hs @@ -134,9 +134,28 @@ atomicSwapIORef (IORef (STRef ref)) new = IO $ \s -> data Box a = Box a --- | Strict version of 'Data.IORef.atomicModifyIORef'. This forces both --- the value stored in the 'IORef' and the value returned. The new value --- is installed in the 'IORef' before the returned value is forced. +-- | A strict version of 'Data.IORef.atomicModifyIORef'. This forces both the +-- value stored in the 'IORef' and the value returned. +-- +-- Conceptually, +-- +-- @ +-- atomicModifyIORef' ref f = do +-- -- Begin atomic block +-- old <- 'readIORef' ref +-- let r = f old +-- new = fst r +-- 'writeIORef' ref new +-- -- End atomic block +-- case r of +-- (!_new, !res) -> pure res +-- @ +-- +-- The actions in the \"atomic block\" are not subject to interference +-- by other threads. In particular, the value in the 'IORef' cannot +-- change between the 'readIORef' and 'writeIORef' invocations. +-- +-- The new value is installed in the 'IORef' before either value is forced. -- So -- -- @atomicModifyIORef' ref (\x -> (x+1, undefined))@ @@ -144,8 +163,18 @@ data Box a = Box a -- will increment the 'IORef' and then throw an exception in the calling -- thread. -- --- This function imposes a memory barrier, preventing reordering; --- see "Data.IORef#memmodel" for details. +-- @atomicModifyIORef' ref (\x -> (undefined, x))@ +-- +-- and +-- +-- @atomicModifyIORef' ref (\_ -> undefined)@ +-- +-- will each raise an exception in the calling thread, but will /also/ +-- install the bottoming value in the 'IORef', where it may be read by +-- other threads. +-- +-- This function imposes a memory barrier, preventing reordering around +-- the \"atomic block\"; see "Data.IORef#memmodel" for details. -- -- @since 4.6.0.0 atomicModifyIORef' :: IORef a -> (a -> (a,b)) -> IO b |