packages feed

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 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)