concurrency 1.1.2.0 → 1.1.2.1
raw patch · 20 files changed
+328/−208 lines, 20 filessetup-changedPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Control.Monad.Conc.Class: class (Applicative m, Monad m, MonadCatch m, MonadThrow m, MonadMask m, MonadSTM (STM m), Ord (ThreadId m), Show (ThreadId m)) => MonadConc m where type STM m :: * -> * type MVar m :: * -> * type CRef m :: * -> * type Ticket m :: * -> * type ThreadId m :: * fork ma = forkWithUnmask (\ _ -> ma) forkWithUnmask = forkWithUnmaskN "" forkWithUnmaskN _ = forkWithUnmask forkOn c ma = forkOnWithUnmask c (\ _ -> ma) forkOnWithUnmask = forkOnWithUnmaskN "" forkOnWithUnmaskN _ = forkOnWithUnmask threadDelay _ = yield newEmptyMVar = newEmptyMVarN "" newEmptyMVarN _ = newEmptyMVar newCRef = newCRefN "" newCRefN _ = newCRef readCRef cref = readForCAS cref >>= peekTicket atomicWriteCRef r a = atomicModifyCRef r $ const (a, ()) modifyCRefCAS_ cref f = modifyCRefCAS cref (\ a -> (f a, ())) readTVarConc = atomically . readTVar where {
+ Control.Monad.Conc.Class: class (Applicative m, Monad m, MonadCatch m, MonadThrow m, MonadMask m, MonadSTM (STM m), Ord (ThreadId m), Show (ThreadId m)) => MonadConc m where type STM m :: * -> * type MVar m :: * -> * type CRef m :: * -> * type Ticket m :: * -> * type ThreadId m :: * fork ma = forkWithUnmask (const ma) forkWithUnmask = forkWithUnmaskN "" forkWithUnmaskN _ = forkWithUnmask forkOn c ma = forkOnWithUnmask c (const ma) forkOnWithUnmask = forkOnWithUnmaskN "" forkOnWithUnmaskN _ = forkOnWithUnmask threadDelay _ = yield newEmptyMVar = newEmptyMVarN "" newEmptyMVarN _ = newEmptyMVar newCRef = newCRefN "" newCRefN _ = newCRef readCRef cref = readForCAS cref >>= peekTicket atomicWriteCRef r a = atomicModifyCRef r $ const (a, ()) modifyCRefCAS_ cref f = modifyCRefCAS cref (\ a -> (f a, ())) readTVarConc = atomically . readTVar where {
Files
- CHANGELOG.markdown +110/−0
- Control/Concurrent/Classy.hs +7/−9
- Control/Concurrent/Classy/Async.hs +40/−45
- Control/Concurrent/Classy/CRef.hs +1/−1
- Control/Concurrent/Classy/Chan.hs +3/−3
- Control/Concurrent/Classy/MVar.hs +14/−12
- Control/Concurrent/Classy/QSem.hs +2/−2
- Control/Concurrent/Classy/QSemN.hs +5/−4
- Control/Concurrent/Classy/STM.hs +7/−9
- Control/Concurrent/Classy/STM/TArray.hs +7/−6
- Control/Concurrent/Classy/STM/TBQueue.hs +2/−2
- Control/Concurrent/Classy/STM/TChan.hs +2/−2
- Control/Concurrent/Classy/STM/TMVar.hs +10/−10
- Control/Concurrent/Classy/STM/TQueue.hs +1/−1
- Control/Concurrent/Classy/STM/TVar.hs +4/−4
- Control/Monad/Conc/Class.hs +28/−28
- Control/Monad/STM/Class.hs +14/−14
- README.markdown +67/−0
- Setup.hs +1/−1
- concurrency.cabal +3/−55
+ CHANGELOG.markdown view
@@ -0,0 +1,110 @@+Release Notes+=============++All notable changes to this project will be documented in this file.++This project is versioned according to the [Package Versioning Policy](https://pvp.haskell.org), the+*de facto* standard Haskell versioning scheme.+++1.1.2.1 [2017-06-07] (tag: [concurrency-1.1.2.1][])+-------++https://hackage.haskell.org/package/concurrency-1.1.2.1++### Changed++- The `isEmptyMVar` function is now implemented using `tryReadMVar` instead of a combination of+ `tryTakeMVar` and `putMVar`. It no longer modifies the contents of the `MVar` and can no longer+ block.++### Miscellaneous++- There is now a changelog.++[concurrency-1.1.2.1]: https://github.com/barrucadu/dejafu/releases/tag/concurrency-1.1.2.1+++---------------------------------------------------------------------------------------------------+++1.1.2.0 [2017-04-05] (tag: [concurrency-1.1.2.0][])+-------++https://hackage.haskell.org/package/concurrency-1.1.2.0++### Control.Concurrent.Classy.Async++- New functions:+ - `uninterruptibleCancel` function, which is `cancel` inside an+ uninterruptible mask.+ - `replicateConcurrently` function, which performs an action many+ times in separate threads.+ - `concurrently_`, `mapConcurrently_`, `forConcurrently_`, and+ `replicateConcurrently_` functions, which discard the result of+ the non-_ version.+- New instances:+ - `Semigroup` instance for `Concurrently` when built with base 4.9.+ - `Monoid` instance for `Concurrently`.++### Control.Monad.Conc.Class++- The `mask_` and `uninterruptibleMask_` functions from Control.Monad.Catch are now re-exported.++### Changed++- The `cancel` and the `withAsync` functions now block until the `Async` action terminates, to match+ changes in the main async package.++### Miscellaneous++- Every definition, class, and instance now has a Haddock "@since" annotation.++[concurrency-1.1.2.0]: https://github.com/barrucadu/dejafu/releases/tag/concurrency-1.1.2.0+++---------------------------------------------------------------------------------------------------+++1.1.1.0 [2017-03-04] (git tag: [concurrency-1.1.1.0][])+-------++https://hackage.haskell.org/package/concurrency-1.1.1.0++### Miscellaneous++- The async-dejafu package has been pulled into this package as the Control.Concurrent.Classy.Async+ module. async-dejafu is now __deprecated__.++[concurrency-1.1.1.0]: https://github.com/barrucadu/dejafu/releases/tag/concurrency-1.1.1.0+++---------------------------------------------------------------------------------------------------+++1.1.0.0 [2017-02-21] (git tag: [concurrency-1.1.0.0][])+-------++https://hackage.haskell.org/package/concurrency-1.1.0.0++### Control.Monad.Conc.Class++- The `MonadConc` class now defines `tryReadMVar`, a non-blocking version of `readMVar` akin to+ `tryTakeMVar`.+- The `MonadConc` class no longer defines `_concMessage`, there is no alternative provided, it is+ just gone.++[concurrency-1.1.0.0]: https://github.com/barrucadu/dejafu/releases/tag/concurrency-1.1.0.0+++---------------------------------------------------------------------------------------------------+++1.0.0.0 [2016-09-10] (git tag: [concurrency-1.0.0.0][])+-------++https://hackage.haskell.org/package/concurrency-1.0.0.0++Initial release. Go read the API docs.++[concurrency-1.0.0.0]: https://github.com/barrucadu/dejafu/releases/tag/concurrency-1.0.0.0
Control/Concurrent/Classy.hs view
@@ -29,12 +29,10 @@ , module Control.Concurrent.Classy.QSemN ) where -import Control.Monad.Conc.Class-import Control.Concurrent.Classy.Chan-import Control.Concurrent.Classy.CRef-import Control.Concurrent.Classy.MVar-import Control.Concurrent.Classy.STM-import Control.Concurrent.Classy.QSem-import Control.Concurrent.Classy.QSemN--{-# ANN module ("HLint: ignore Use import/export shortcut" :: String) #-}+import Control.Concurrent.Classy.Chan+import Control.Concurrent.Classy.CRef+import Control.Concurrent.Classy.MVar+import Control.Concurrent.Classy.QSem+import Control.Concurrent.Classy.QSemN+import Control.Concurrent.Classy.STM+import Control.Monad.Conc.Class
Control/Concurrent/Classy/Async.hs view
@@ -77,18 +77,21 @@ , Concurrently(..) ) where -import Control.Applicative-import Control.Concurrent.Classy.STM.TMVar (newEmptyTMVar, putTMVar, readTMVar)-import Control.Exception (AsyncException(ThreadKilled), BlockedIndefinitelyOnSTM(..), Exception, SomeException)-import Control.Monad-import Control.Monad.Catch (finally, try, onException)-import Control.Monad.Conc.Class-import Control.Monad.STM.Class-import Data.Foldable (foldMap)-import Data.Traversable+import Control.Applicative+import Control.Concurrent.Classy.STM.TMVar (newEmptyTMVar, putTMVar,+ readTMVar)+import Control.Exception (AsyncException(ThreadKilled),+ BlockedIndefinitelyOnSTM(..),+ Exception, SomeException)+import Control.Monad+import Control.Monad.Catch (finally, onException, try)+import Control.Monad.Conc.Class+import Control.Monad.STM.Class+import Data.Foldable (foldMap)+import Data.Traversable #if MIN_VERSION_base(4,9,0)-import Data.Semigroup (Semigroup(..))+import Data.Semigroup (Semigroup(..)) #endif -----------------------------------------------------------------------------------------@@ -142,7 +145,7 @@ -- | @since 1.1.1.0 instance MonadConc m => Applicative (Concurrently m) where- pure = Concurrently . return+ pure = Concurrently . pure Concurrently fs <*> Concurrently as = Concurrently $ (\(f, a) -> f a) <$> concurrently fs as@@ -199,8 +202,7 @@ asyncUsing doFork action = do var <- atomically newEmptyTMVar tid <- mask $ \restore -> doFork $ try (restore action) >>= atomically . putTMVar var-- return $ Async tid (readTMVar var)+ pure (Async tid (readTMVar var)) -- | Fork a thread with the given forking function and give it an -- action to unmask exceptions@@ -208,8 +210,7 @@ asyncUnmaskUsing doFork action = do var <- atomically newEmptyTMVar tid <- doFork $ \restore -> try (action restore) >>= atomically . putTMVar var-- return $ Async tid (readTMVar var)+ pure (Async tid (readTMVar var)) -- | Spawn an asynchronous action in a separate thread, and pass its -- @Async@ handle to the supplied function. When the function returns@@ -245,36 +246,30 @@ withAsyncOnWithUnmask :: MonadConc m => Int -> ((forall x. m x -> m x) -> m a) -> (Async m a -> m b) -> m b withAsyncOnWithUnmask i = withAsyncUnmaskUsing (forkOnWithUnmask i) --- | Fork a thread with the given forking function and kill it when--- the inner action completes.------ The 'bracket' version appears to hang, even with just IO stuff and--- using the normal async package. Curious.+-- | Helper for 'withAsync' and 'withAsyncOn': fork a thread with the+-- given forking function and kill it when the inner action completes. withAsyncUsing :: MonadConc m => (m () -> m (ThreadId m)) -> m a -> (Async m a -> m b) -> m b withAsyncUsing doFork action inner = do var <- atomically newEmptyTMVar tid <- mask $ \restore -> doFork $ try (restore action) >>= atomically . putTMVar var-- let a = Async tid (readTMVar var)-- res <- inner a `catchAll` (\e -> uninterruptibleCancel a >> throw e)- cancel a-- return res+ withAsyncDo (Async tid (readTMVar var)) inner --- | Fork a thread with the given forking function, give it an action--- to unmask exceptions, and kill it when the inner action completed.+-- | Helper for 'withAsyncWithUnmask' and 'withAsyncOnWithUnmask':+-- fork a thread with the given forking function, give it an action to+-- unmask exceptions, and kill it when the inner action completed. withAsyncUnmaskUsing :: MonadConc m => (((forall x. m x -> m x) -> m ()) -> m (ThreadId m)) -> ((forall x. m x -> m x) -> m a) -> (Async m a -> m b) -> m b withAsyncUnmaskUsing doFork action inner = do var <- atomically newEmptyTMVar tid <- doFork $ \restore -> try (action restore) >>= atomically . putTMVar var-- let a = Async tid (readTMVar var)+ withAsyncDo (Async tid (readTMVar var)) inner +-- | Helper for 'withAsyncUsing' and 'withAsyncUnmaskUsing': run the+-- inner action and kill the async thread when done.+withAsyncDo :: MonadConc m => Async m a -> (Async m a -> m b) -> m b+withAsyncDo a inner = do res <- inner a `catchAll` (\e -> uninterruptibleCancel a >> throw e) cancel a-- return res+ pure res catchAll :: MonadConc m => m a -> (SomeException -> m a) -> m a catchAll = catch@@ -298,7 +293,7 @@ waitSTM :: MonadConc m => Async m a -> STM m a waitSTM a = do r <- waitCatchSTM a- either throwSTM return r+ either throwSTM pure r -- | Check whether an 'Async' has completed yet. If it has not -- completed yet, then the result is @Nothing@, otherwise the result@@ -315,7 +310,7 @@ -- -- @since 1.1.1.0 pollSTM :: MonadConc m => Async m a -> STM m (Maybe (Either SomeException a))-pollSTM (Async _ w) = (Just <$> w) `orElse` return Nothing+pollSTM (Async _ w) = (Just <$> w) `orElse` pure Nothing -- | Wait for an asynchronous action to complete, and return either -- @Left e@ if the action raised an exception @e@, or @Right a@ if it@@ -391,7 +386,7 @@ -- -- @since 1.1.1.0 waitAnySTM :: MonadConc m => [Async m a] -> STM m (Async m a, a)-waitAnySTM = foldr (orElse . (\a -> do r <- waitSTM a; return (a, r))) retry+waitAnySTM = foldr (orElse . (\a -> do r <- waitSTM a; pure (a, r))) retry -- | Wait for any of the supplied asynchronous operations to complete. -- The value returned is a pair of the 'Async' that completed, and the@@ -409,7 +404,7 @@ -- -- @since 1.1.1.0 waitAnyCatchSTM :: MonadConc m => [Async m a] -> STM m (Async m a, Either SomeException a)-waitAnyCatchSTM = foldr (orElse . (\a -> do r <- waitCatchSTM a; return (a, r))) retry+waitAnyCatchSTM = foldr (orElse . (\a -> do r <- waitCatchSTM a; pure (a, r))) retry -- | Like 'waitAny', but also cancels the other asynchronous -- operations as soon as one has completed.@@ -503,7 +498,7 @@ waitBothSTM left right = do a <- waitSTM left `orElse` (waitSTM right >> retry) b <- waitSTM right- return (a, b)+ pure (a, b) -------------------------------------------------------------------------------@@ -521,7 +516,7 @@ r <- atomically w case r of Left e -> throwTo me e- _ -> return ()+ _ -> pure () -- | Link two @Async@s together, such that if either raises an -- exception, the same exception is re-thrown in the other @Async@.@@ -534,7 +529,7 @@ case r of Left (Left e) -> throwTo tr e Right (Left e) -> throwTo tl e- _ -> return ()+ _ -> pure () -- | Fork a thread that runs the supplied action, and if it raises an -- exception, re-runs the action. The thread terminates only when the@@ -545,7 +540,7 @@ r <- (try :: MonadConc m => m a -> m (Either SomeException a)) $ restore action case r of Left _ -> go- _ -> return ()+ _ -> pure () in fork go @@ -567,7 +562,7 @@ e <- takeMVar m case e of Left ex -> throw ex- Right r -> return r+ Right r -> pure r -- | Like 'race', but the result is ignored. --@@ -593,8 +588,8 @@ -- @since 1.1.1.0 concurrently :: MonadConc m => m a -> m b -> m (a, b) concurrently left right = concurrently' left right (collect []) where- collect [Left a, Right b] _ = return (a, b)- collect [Right b, Left a] _ = return (a, b)+ collect [Left a, Right b] _ = pure (a, b)+ collect [Right b, Left a] _ = pure (a, b) collect xs m = do e <- takeMVar m case e of@@ -633,7 +628,7 @@ stop - return r+ pure r -- | Maps a @MonadConc@-performing function over any @Traversable@ -- data type, performing all the @MonadConc@ actions concurrently, and
Control/Concurrent/Classy/CRef.hs view
@@ -80,7 +80,7 @@ -- memory barrier. ) where -import Control.Monad.Conc.Class+import Control.Monad.Conc.Class -- | Mutate the contents of a @CRef@. --
Control/Concurrent/Classy/Chan.hs view
@@ -27,9 +27,9 @@ , writeList2Chan ) where -import Control.Concurrent.Classy.MVar-import Control.Monad.Catch (mask_)-import Control.Monad.Conc.Class (MonadConc)+import Control.Concurrent.Classy.MVar+import Control.Monad.Catch (mask_)+import Control.Monad.Conc.Class (MonadConc) -- | 'Chan' is an abstract type representing an unbounded FIFO -- channel.
Control/Concurrent/Classy/MVar.hs view
@@ -48,8 +48,9 @@ , modifyMVarMasked ) where -import Control.Monad.Catch (mask_, onException)-import Control.Monad.Conc.Class+import Control.Monad.Catch (mask_, onException)+import Control.Monad.Conc.Class+import Data.Maybe (isJust) -- | Swap the contents of a @MVar@, and return the value taken. This -- function is atomic only if there are no other producers fro this@@ -60,17 +61,18 @@ swapMVar cvar a = mask_ $ do old <- takeMVar cvar putMVar cvar a- return old+ pure old -- | Check if a @MVar@ is empty. --+-- The boolean value returned is just a snapshot of the state of the+-- @MVar@, it may have been emptied (or filled) by the time you+-- actually access it. Generally prefer 'tryPutMVar', 'tryTakeMVar',+-- and 'tryReadMVar'.+-- -- @since 1.0.0.0 isEmptyMVar :: MonadConc m => MVar m a -> m Bool-isEmptyMVar cvar = do- val <- tryTakeMVar cvar- case val of- Just val' -> putMVar cvar val' >> return True- Nothing -> return False+isEmptyMVar = fmap isJust . tryReadMVar -- | Operate on the contents of a @MVar@, replacing the contents after -- finishing. This operation is exception-safe: it will replace the@@ -85,7 +87,7 @@ out <- restore (f val) `onException` putMVar cvar val putMVar cvar val - return out+ pure out -- | Like 'withMVar', but the @IO@ action in the second argument is -- executed with asynchronous exceptions masked.@@ -98,7 +100,7 @@ out <- f val `onException` putMVar cvar val putMVar cvar val - return out+ pure out -- | An exception-safe wrapper for modifying the contents of a @MVar@. -- Like 'withMVar', 'modifyMVar' will replace the original contents of@@ -121,7 +123,7 @@ val <- takeMVar cvar (val', out) <- restore (f val) `onException` putMVar cvar val putMVar cvar val'- return out+ pure out -- | Like 'modifyMVar_', but the @IO@ action in the second argument is -- executed with asynchronous exceptions masked.@@ -141,4 +143,4 @@ val <- takeMVar cvar (val', out) <- f val `onException` putMVar cvar val putMVar cvar val'- return out+ pure out
Control/Concurrent/Classy/QSem.hs view
@@ -15,8 +15,8 @@ , signalQSem ) where -import Control.Concurrent.Classy.QSemN-import Control.Monad.Conc.Class (MonadConc)+import Control.Concurrent.Classy.QSemN+import Control.Monad.Conc.Class (MonadConc) -- | @QSem@ is a quantity semaphore in which the resource is acquired -- and released in units of one. It provides guaranteed FIFO ordering
Control/Concurrent/Classy/QSemN.hs view
@@ -16,10 +16,11 @@ , signalQSemN ) where -import Control.Monad.Conc.Class (MonadConc)-import Control.Concurrent.Classy.MVar-import Control.Monad.Catch (mask_, onException, uninterruptibleMask_)-import Data.Maybe+import Control.Concurrent.Classy.MVar+import Control.Monad.Catch (mask_, onException,+ uninterruptibleMask_)+import Control.Monad.Conc.Class (MonadConc)+import Data.Maybe -- | 'QSemN' is a quantity semaphore in which the resource is aqcuired -- and released in units of one. It provides guaranteed FIFO ordering
Control/Concurrent/Classy/STM.hs view
@@ -17,12 +17,10 @@ , module Control.Concurrent.Classy.STM.TArray ) where -import Control.Monad.STM.Class-import Control.Concurrent.Classy.STM.TVar-import Control.Concurrent.Classy.STM.TMVar-import Control.Concurrent.Classy.STM.TChan-import Control.Concurrent.Classy.STM.TQueue-import Control.Concurrent.Classy.STM.TBQueue-import Control.Concurrent.Classy.STM.TArray--{-# ANN module ("HLint: ignore Use import/export shortcut" :: String) #-}+import Control.Concurrent.Classy.STM.TArray+import Control.Concurrent.Classy.STM.TBQueue+import Control.Concurrent.Classy.STM.TChan+import Control.Concurrent.Classy.STM.TMVar+import Control.Concurrent.Classy.STM.TQueue+import Control.Concurrent.Classy.STM.TVar+import Control.Monad.STM.Class
Control/Concurrent/Classy/STM/TArray.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-} -- | -- Module : Control.Concurrent.Classy.STM.@@ -15,12 +16,12 @@ -- an @Eq@ constraint. module Control.Concurrent.Classy.STM.TArray (TArray) where -import Data.Array (Array, bounds)-import Data.Array.Base (listArray, arrEleBottom, unsafeAt, MArray(..),- IArray(numElements))-import Data.Ix (rangeSize)+import Data.Array (Array, bounds)+import Data.Array.Base (IArray(numElements), MArray(..),+ arrEleBottom, listArray, unsafeAt)+import Data.Ix (rangeSize) -import Control.Monad.STM.Class+import Control.Monad.STM.Class -- | @TArray@ is a transactional array, supporting the usual 'MArray' -- interface for mutable arrays.
Control/Concurrent/Classy/STM/TBQueue.hs view
@@ -33,7 +33,7 @@ , isFullTBQueue ) where -import Control.Monad.STM.Class+import Control.Monad.STM.Class -- | 'TBQueue' is an abstract type representing a bounded FIFO -- channel.@@ -113,7 +113,7 @@ peekTBQueue c = do x <- readTBQueue c unGetTBQueue c x- return x+ pure x -- | A version of 'peekTBQueue' which does not retry. Instead it -- returns @Nothing@ if no value is available.
Control/Concurrent/Classy/STM/TChan.hs view
@@ -32,7 +32,7 @@ , isEmptyTChan ) where -import Control.Monad.STM.Class+import Control.Monad.STM.Class -- | 'TChan' is an abstract type representing an unbounded FIFO -- channel.@@ -125,7 +125,7 @@ dupTChan (TChan _ writeT) = do hole <- readTVar writeT readT' <- newTVar hole- return (TChan readT' writeT)+ pure (TChan readT' writeT) -- | Put a data item back onto a channel, where it will be the next -- item read.
Control/Concurrent/Classy/STM/TMVar.hs view
@@ -29,9 +29,9 @@ , swapTMVar ) where -import Control.Monad (liftM, when, unless)-import Control.Monad.STM.Class-import Data.Maybe (isJust, isNothing)+import Control.Monad (liftM, unless, when)+import Control.Monad.STM.Class+import Data.Maybe (isJust, isNothing) -- | A @TMVar@ is like an @MVar@ or a @mVar@, but using transactional -- memory. As transactions are atomic, this makes dealing with@@ -57,7 +57,7 @@ newTMVarN n a = do let n' = if null n then "ctmvar" else "ctmvar-" ++ n ctvar <- newTVarN n' $ Just a- return $ TMVar ctvar+ pure (TMVar ctvar) -- | Create a new empty 'TMVar'. --@@ -75,7 +75,7 @@ newEmptyTMVarN n = do let n' = if null n then "ctmvar" else "ctmvar-" ++ n ctvar <- newTVarN n' Nothing- return $ TMVar ctvar+ pure (TMVar ctvar) -- | Take the contents of a 'TMVar', or 'retry' if it is empty. --@@ -83,7 +83,7 @@ takeTMVar :: MonadSTM stm => TMVar stm a -> stm a takeTMVar ctmvar = do taken <- tryTakeTMVar ctmvar- maybe retry return taken+ maybe retry pure taken -- | Write to a 'TMVar', or 'retry' if it is full. --@@ -99,7 +99,7 @@ readTMVar :: MonadSTM stm => TMVar stm a -> stm a readTMVar ctmvar = do readed <- tryReadTMVar ctmvar- maybe retry return readed+ maybe retry pure readed -- | Try to take the contents of a 'TMVar', returning 'Nothing' if it -- is empty.@@ -109,7 +109,7 @@ tryTakeTMVar (TMVar ctvar) = do val <- readTVar ctvar when (isJust val) $ writeTVar ctvar Nothing- return val+ pure val -- | Try to write to a 'TMVar', returning 'False' if it is full. --@@ -118,7 +118,7 @@ tryPutTMVar (TMVar ctvar) a = do val <- readTVar ctvar when (isNothing val) $ writeTVar ctvar (Just a)- return $ isNothing val+ pure (isNothing val) -- | Try to read from a 'TMVar' without emptying, returning 'Nothing' -- if it is empty.@@ -141,4 +141,4 @@ swapTMVar ctmvar a = do val <- takeTMVar ctmvar putTMVar ctmvar a- return val+ pure val
Control/Concurrent/Classy/STM/TQueue.hs view
@@ -36,7 +36,7 @@ , isEmptyTQueue ) where -import Control.Monad.STM.Class+import Control.Monad.STM.Class -- | 'TQueue' is an abstract type representing an unbounded FIFO channel. --
Control/Concurrent/Classy/STM/TVar.hs view
@@ -25,9 +25,9 @@ , registerDelay ) where -import Control.Monad.STM.Class-import Control.Monad.Conc.Class-import Data.Functor (void)+import Control.Monad.Conc.Class+import Control.Monad.STM.Class+import Data.Functor (void) -- * @TVar@s @@ -54,7 +54,7 @@ swapTVar ctvar a = do old <- readTVar ctvar writeTVar ctvar a- return old+ pure old -- | Set the value of returned 'TVar' to @True@ after a given number -- of microseconds. The caveats associated with 'threadDelay' also
Control/Monad/Conc/Class.hs view
@@ -66,32 +66,32 @@ ) where -- for the class and utilities-import Control.Exception (Exception, AsyncException(ThreadKilled), SomeException)-import Control.Monad.Catch (MonadCatch, MonadThrow, MonadMask)-import qualified Control.Monad.Catch as Ca-import Control.Monad.STM.Class (MonadSTM, TVar, readTVar)-import Control.Monad.Trans.Control (MonadTransControl, StT, liftWith)-import Data.Proxy (Proxy(..))+import Control.Exception (AsyncException(ThreadKilled),+ Exception, SomeException)+import Control.Monad.Catch (MonadCatch, MonadMask,+ MonadThrow)+import qualified Control.Monad.Catch as Ca+import Control.Monad.STM.Class (MonadSTM, TVar, readTVar)+import Control.Monad.Trans.Control (MonadTransControl, StT, liftWith)+import Data.Proxy (Proxy(..)) -- for the 'IO' instance-import qualified Control.Concurrent as IO-import qualified Control.Concurrent.STM.TVar as IO-import qualified Control.Monad.STM as IO-import qualified Data.Atomics as IO-import qualified Data.IORef as IO+import qualified Control.Concurrent as IO+import qualified Control.Concurrent.STM.TVar as IO+import qualified Control.Monad.STM as IO+import qualified Data.Atomics as IO+import qualified Data.IORef as IO -- for the transformer instances-import Control.Monad.Reader (ReaderT)-import Control.Monad.Trans (lift)-import Control.Monad.Trans.Identity (IdentityT)-import qualified Control.Monad.RWS.Lazy as RL-import qualified Control.Monad.RWS.Strict as RS-import qualified Control.Monad.State.Lazy as SL-import qualified Control.Monad.State.Strict as SS-import qualified Control.Monad.Writer.Lazy as WL-import qualified Control.Monad.Writer.Strict as WS--{-# ANN module ("HLint: ignore Use const" :: String) #-}+import Control.Monad.Reader (ReaderT)+import qualified Control.Monad.RWS.Lazy as RL+import qualified Control.Monad.RWS.Strict as RS+import qualified Control.Monad.State.Lazy as SL+import qualified Control.Monad.State.Strict as SS+import Control.Monad.Trans (lift)+import Control.Monad.Trans.Identity (IdentityT)+import qualified Control.Monad.Writer.Lazy as WL+import qualified Control.Monad.Writer.Strict as WS -- | @MonadConc@ is an abstraction over GHC's typical concurrency -- abstraction. It captures the interface of concurrency monads in@@ -167,11 +167,11 @@ -- | Fork a computation to happen concurrently. Communication may -- happen over @MVar@s. --- -- > fork ma = forkWithUnmask (\_ -> ma)+ -- > fork ma = forkWithUnmask (const ma) -- -- @since 1.0.0.0 fork :: m () -> m (ThreadId m)- fork ma = forkWithUnmask (\_ -> ma)+ fork ma = forkWithUnmask (const ma) -- | Like 'fork', but the child thread is passed a function that can -- be used to unmask asynchronous exceptions. This function should@@ -202,11 +202,11 @@ -- implementation dependent. The int is interpreted modulo to the -- total number of capabilities as returned by 'getNumCapabilities'. --- -- > forkOn c ma = forkOnWithUnmask c (\_ -> ma)+ -- > forkOn c ma = forkOnWithUnmask c (const ma) -- -- @since 1.0.0.0 forkOn :: Int -> m () -> m (ThreadId m)- forkOn c ma = forkOnWithUnmask c (\_ -> ma)+ forkOn c ma = forkOnWithUnmask c (const ma) -- | Like 'forkWithUnmask', but the child thread is pinned to the -- given CPU, as with 'forkOn'.@@ -477,7 +477,7 @@ -- -- @since 1.0.0.0 forkN :: MonadConc m => String -> m () -> m (ThreadId m)-forkN name ma = forkWithUnmaskN name (\_ -> ma)+forkN name ma = forkWithUnmaskN name (const ma) -- | Like 'forkOn', but the thread is given a name which may be used -- to present more useful debugging information.@@ -488,7 +488,7 @@ -- -- @since 1.0.0.0 forkOnN :: MonadConc m => String -> Int -> m () -> m (ThreadId m)-forkOnN name i ma = forkOnWithUnmaskN name i (\_ -> ma)+forkOnN name i ma = forkOnWithUnmaskN name i (const ma) -- Bound Threads
Control/Monad/STM/Class.hs view
@@ -31,21 +31,21 @@ , liftedOrElse ) where -import Control.Exception (Exception)-import Control.Monad (unless)-import Control.Monad.Reader (ReaderT)-import Control.Monad.Trans (lift)-import Control.Monad.Trans.Control (MonadTransControl, StT, liftWith)-import Control.Monad.Trans.Identity (IdentityT)+import Control.Exception (Exception)+import Control.Monad (unless)+import Control.Monad.Reader (ReaderT)+import Control.Monad.Trans (lift)+import Control.Monad.Trans.Control (MonadTransControl, StT, liftWith)+import Control.Monad.Trans.Identity (IdentityT) -import qualified Control.Concurrent.STM as STM-import qualified Control.Monad.Catch as Ca-import qualified Control.Monad.RWS.Lazy as RL-import qualified Control.Monad.RWS.Strict as RS-import qualified Control.Monad.State.Lazy as SL-import qualified Control.Monad.State.Strict as SS-import qualified Control.Monad.Writer.Lazy as WL-import qualified Control.Monad.Writer.Strict as WS+import qualified Control.Concurrent.STM as STM+import qualified Control.Monad.Catch as Ca+import qualified Control.Monad.RWS.Lazy as RL+import qualified Control.Monad.RWS.Strict as RS+import qualified Control.Monad.State.Lazy as SL+import qualified Control.Monad.State.Strict as SS+import qualified Control.Monad.Writer.Lazy as WL+import qualified Control.Monad.Writer.Strict as WS -- | @MonadSTM@ is an abstraction over 'STM'. --
+ README.markdown view
@@ -0,0 +1,67 @@+concurrency+===========++A typeclass abstraction over much of Control.Concurrent (and some+extras!). If you're looking for a general introduction to Haskell+concurrency, you should check out the excellent+[Parallel and Concurrent Programming in Haskell][parconc], by Simon+Marlow. If you are already familiar with concurrent Haskell, just+change all the imports from Control.Concurrent.* to+Control.Concurrent.Classy.* and fix the type errors.++A brief list of supported functionality:++- Threads: the `forkIO*` and `forkOn*` functions, although bound+ threads are not supported.+- Getting and setting capablities.+- Yielding and delaying.+- Mutable state: STM, `MVar`, and `IORef`.+- Atomic compare-and-swap for `IORef`.+- Exceptions.+- All of the data structures in Control.Concurrent.* and+ Control.Concurrent.STM.* have typeclass-abstracted equivalents.+- A reimplementation of the [async][] package, providing a+ higher-level interface over threads, allowing users to conveniently+ run `MonadConc` operations asynchronously and wait for their+ results.++This is quite a rich set of functionality, although it is not+complete. If there is something else you need, file an issue!++This used to be part of dejafu, but with the dejafu-0.4.0.0 release,+it was split out into its own package.++The documentation of the latest developmental version is+[available online][docs].++Why this and not something else?+--------------------------------++- **Why not base:** like lifted-base, concurrency uses typeclasses to+ make function types more generic. This automatically eliminates+ calls to `lift` in many cases, resulting in clearer and simpler+ code.++- **Why not lifted-base:** fundamentally, lifted-base is still using+ actual threads and actual mutable variables. When using a+ concurrency-specific typeclass, this isn't necessarily the case. The+ dejafu library provides non-IO-based implementations to allow+ testing concurrent programs.++- **Why not IOSpec:** IOSpec provides many of the operations this+ library does, however it uses a free monad to do so, which has extra+ allocation overhead. Furthermore, it does not expose enough of the+ internals in order to accurately test real-execution semantics, such+ as relaxed memory.++Contributing+------------++Bug reports, pull requests, and comments are very welcome!++Feel free to contact me on GitHub, through IRC (#haskell on freenode),+or email (mike@barrucadu.co.uk).++[docs]: https://docs.barrucadu.co.uk/concurrency/dejafu-0.4+[async]: https://hackage.haskell.org/package/async+[parconc]: http://chimera.labs.oreilly.com/books/1230000000929
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple+import Distribution.Simple main = defaultMain
concurrency.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: concurrency-version: 1.1.2.0+version: 1.1.2.1 synopsis: Typeclasses, functions, and data types for concurrency and STM. description:@@ -13,58 +13,6 @@ already familiar with concurrent Haskell, just change all the imports from Control.Concurrent.* to Control.Concurrent.Classy.* and fix the type errors.- .- A brief list of supported functionality:- .- * Threads: the @forkIO*@ and @forkOn*@ functions, although bound- threads are not supported.- .- * Getting and setting capablities.- .- * Yielding and delaying.- .- * Mutable state: STM, @MVar@, and @IORef@.- .- * Atomic compare-and-swap for @IORef@.- .- * Exceptions.- .- * All of the data structures in Control.Concurrent.* and- Control.Concurrent.STM.* have typeclass-abstracted equivalents.- .- * A reimplementation of the- <https://hackage.haskell.org/package/async async> package,- providing a higher-level interface over threads, allowing users to- conveniently run @MonadConc@ operations asynchronously and wait- for their results.- .- This is quite a rich set of functionality, although it is not- complete. If there is something else you need, file an issue!- .- This used to be part of dejafu, but with the dejafu-0.4.0.0 release,- it was split out into its own package.- .- == Why this and not something else?- .- * Why not base: like lifted-base, concurrency uses typeclasses to- make function types more generic. This automatically eliminates- calls to `lift` in many cases, resulting in clearer and simpler- code.- .- * Why not lifted-base: fundamentally, lifted-base is still using- actual threads and actual mutable variables. When using a- concurrency-specific typeclass, this isn't necessarily the case.- The dejafu library provides non-IO-based implementations to allow- testing concurrent programs.- .- * Why not IOSpec: IOSpec provides many of the operations this- library does, however it uses a free monad to do so, which has- extra allocation overhead. Furthermore, it does not expose enough- of the internals in order to accurately test real-execution- semantics, such as relaxed memory.- .- See the <https://github.com/barrucadu/dejafu README> for more- details. homepage: https://github.com/barrucadu/dejafu license: MIT@@ -74,7 +22,7 @@ -- copyright: category: Concurrency build-type: Simple--- extra-source-files: +extra-source-files: README.markdown CHANGELOG.markdown cabal-version: >=1.10 source-repository head@@ -84,7 +32,7 @@ source-repository this type: git location: https://github.com/barrucadu/dejafu.git- tag: concurrency-1.1.2.0+ tag: concurrency-1.1.2.1 library exposed-modules: Control.Monad.Conc.Class