atomic-modify (empty) → 0.1.0.0
raw patch · 3 files changed
+154/−0 lines, 3 filesdep +basedep +stm
Dependencies added: base, stm
Files
- atomic-modify.cabal +31/−0
- license.txt +13/−0
- src/Control/Concurrent/AtomicModify.hs +110/−0
+ atomic-modify.cabal view
@@ -0,0 +1,31 @@+-- This file has been generated from package.yaml by hpack version 0.17.0.+--+-- see: https://github.com/sol/hpack++name: atomic-modify+version: 0.1.0.0+synopsis: A typeclass for mutable references that have an atomic modify operation.++description: A typeclass for mutable references that have an atomic modify operation. Generalizes atomic modify operations in IO and STM contexts for IORef, MVar, TVar, and TMVar.+category: Concurrency+homepage: https://github.com/chris-martin/haskell-libraries+author: Chris Martin <ch.martin@gmail.com>+maintainer: Chris Martin <ch.martin@gmail.com>+license: Apache-2.0+license-file: license.txt+build-type: Simple+cabal-version: >= 1.10++library+ hs-source-dirs:+ src+ default-extensions: NoImplicitPrelude+ ghc-options: -Wall+ build-depends:+ base >= 4.9 && < 4.10+ , stm+ exposed-modules:+ Control.Concurrent.AtomicModify+ other-modules:+ Paths_atomic_modify+ default-language: Haskell2010
+ license.txt view
@@ -0,0 +1,13 @@+Copyright 2017 Chris Martin++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.
+ src/Control/Concurrent/AtomicModify.hs view
@@ -0,0 +1,110 @@+{- |++Provides 'AtomicModify', a typeclass for mutable references that have an atomic+modify operations. This generalizes atomic modify operations in 'IO' and 'STM'+contexts for 'IORef', 'MVar', 'TVar', and 'TMVar'.++* 'IORef' and 'MVar' can be modified in 'IO'.+* 'TVar' and 'TMVar' can be modified in 'IO' or 'STM'.++-}++{-# LANGUAGE MultiParamTypeClasses #-}++module Control.Concurrent.AtomicModify+ ( AtomicModify (..)+ , atomicModifyStrict_+ , atomicModifyLazy_+ ) where++import Control.Concurrent.MVar (MVar, modifyMVar)+import Control.Concurrent.STM (STM, TMVar, TVar, atomically, putTMVar, readTVar,+ takeTMVar, writeTVar)+import Data.IORef (IORef, atomicModifyIORef, atomicModifyIORef')+import Prelude (IO, pure, ($), ($!))++{- |+A typeclass for mutable references that have an atomic modify operation.++Type variables:++* @ref@ - The reference (e.g. 'IORef', 'TVar', 'MVar', 'TMVar')+* @m@ - The monad in which the modification takes place (e.g. 'IO', 'STM')++As the name "atomic" implies, these functions are useful for using mutable+references in a safe way to prevent race conditions in a multithreaded+program.+-}+class AtomicModify ref m where++ -- | Atomically modify the contents of a @ref@ (type @a@) and produce a+ -- value (type @b@). This is strict; it forces the value stored in the @ref@+ -- as well as the value returned.+ atomicModifyStrict :: ref a -> (a -> (a, b)) -> m b++ -- | Atomically modify the contents of a @ref@ (type @a@) and produce a+ -- value (type @b@). This is lazy, which means if the program calls+ -- 'atomicModifyLazy' many times, but seldomly uses the value, thunks will+ -- pile up in memory resulting in a space leak.+ atomicModifyLazy :: ref a -> (a -> (a, b)) -> m b++-- | Atomically modify the contents of a @ref@. This is strict; it forces the+-- value stored in the @ref@ as well as the value returned.+atomicModifyStrict_ :: AtomicModify v m => v a -> (a -> a) -> m ()+atomicModifyStrict_ ref f = atomicModifyStrict ref (\a -> (f a, ()))++-- | Atomically modify the contents of a @ref@ (type @a@) and produce a value+-- (type @b@). This is lazy, which means if the program calls+-- 'atomicModifyLazy_' many times, but seldomly uses the value, thunks will pile+-- up in memory resulting in a space leak.+atomicModifyLazy_ :: AtomicModify v m => v a -> (a -> a) -> m ()+atomicModifyLazy_ ref f = atomicModifyLazy ref (\a -> (f a, ()))+++--------------------------------------------------------------------------------+-- Instances+--------------------------------------------------------------------------------++instance AtomicModify IORef IO where+ atomicModifyLazy ref f = atomicModifyIORef ref f+ atomicModifyStrict ref f = atomicModifyIORef' ref f++instance AtomicModify MVar IO where+ atomicModifyLazy ref f = modifyMVar ref (\x -> pure $ f x)+ atomicModifyStrict ref f = modifyMVar ref (\x -> pure $! f x)++instance AtomicModify TVar STM where++ atomicModifyLazy ref f = do+ a <- readTVar ref+ let (a', b) = f a+ writeTVar ref a'+ pure b++ atomicModifyStrict ref f = do+ a <- readTVar ref+ let (a', b) = f a+ writeTVar ref $! a'+ pure $! b++instance AtomicModify TMVar STM where++ atomicModifyLazy ref f = do+ a <- takeTMVar ref+ let (a', b) = f a+ putTMVar ref a'+ pure b++ atomicModifyStrict ref f = do+ a <- takeTMVar ref+ let (a', b) = f a+ putTMVar ref $! a'+ pure $! b++instance AtomicModify TVar IO where+ atomicModifyLazy ref f = atomically (atomicModifyLazy ref f)+ atomicModifyStrict ref f = atomically (atomicModifyStrict ref f)++instance AtomicModify TMVar IO where+ atomicModifyLazy ref f = atomically (atomicModifyLazy ref f)+ atomicModifyStrict ref f = atomically (atomicModifyStrict ref f)