1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
{-# LANGUAGE CPP, NoImplicitPrelude, RankNTypes, ImpredicativeTypes #-}
#if __GLASGOW_HASKELL__ >= 701
{-# LANGUAGE Trustworthy #-}
#endif
--------------------------------------------------------------------------------
-- |
-- Module : Control.Concurrent.Thread
-- Copyright : (c) 2010-2012 Bas van Dijk & Roel van Dijk
-- License : BSD3 (see the file LICENSE)
-- Maintainer : Bas van Dijk <v.dijk.bas@gmail.com>
-- , Roel van Dijk <vandijk.roel@gmail.com>
--
-- Standard threads extended with the ability to /wait/ for their return value.
--
-- This module exports equivalently named functions from @Control.Concurrent@
-- (and @GHC.Conc@). Avoid ambiguities by importing this module qualified. May
-- we suggest:
--
-- @
-- import qualified Control.Concurrent.Thread as Thread ( ... )
-- @
--
-- The following is an example how to use this module:
--
-- @
--
-- import qualified Control.Concurrent.Thread as Thread ( 'forkIO', 'result' )
--
-- main = do (tid, wait) <- Thread.'forkIO' $ do x <- someExpensiveComputation
-- return x
-- doSomethingElse
-- x <- Thread.'result' =<< 'wait'
-- doSomethingWithResult x
-- @
--
--------------------------------------------------------------------------------
module Control.Concurrent.Thread
( -- * Forking threads
forkIO
, forkOS
, forkOn
, forkIOWithUnmask
, forkOnWithUnmask
-- * Results
, Result
, result
) where
--------------------------------------------------------------------------------
-- Imports
--------------------------------------------------------------------------------
-- from base:
import qualified Control.Concurrent ( forkOS
, forkIOWithUnmask
, forkOnWithUnmask
)
import Control.Concurrent ( ThreadId )
import Control.Concurrent.MVar ( newEmptyMVar, putMVar, readMVar )
import Control.Exception ( SomeException, try, throwIO, mask )
import Control.Monad ( return, (>>=) )
import Data.Either ( Either(..), either )
import Data.Function ( (.), ($) )
import Data.Int ( Int )
import System.IO ( IO )
-- from threads:
import Control.Concurrent.Raw ( rawForkIO, rawForkOn )
--------------------------------------------------------------------------------
-- * Forking threads
--------------------------------------------------------------------------------
-- | Like @Control.Concurrent.'Control.Concurrent.forkIO'@ but returns
-- a computation that when executed blocks until the thread terminates
-- then returns the final value of the thread.
forkIO :: IO a -> IO (ThreadId, IO (Result a))
forkIO = fork rawForkIO
-- | Like @Control.Concurrent.'Control.Concurrent.forkOS'@ but returns
-- a computation that when executed blocks until the thread terminates
-- then returns the final value of the thread.
forkOS :: IO a -> IO (ThreadId, IO (Result a))
forkOS = fork Control.Concurrent.forkOS
-- | Like @Control.Concurrent.'Control.Concurrent.forkOn'@ but returns
-- a computation that when executed blocks until the thread terminates
-- then returns the final value of the thread.
forkOn :: Int -> IO a -> IO (ThreadId, IO (Result a))
forkOn = fork . rawForkOn
-- | Like @Control.Concurrent.'Control.Concurrent.forkIOWithUnmask'@ but returns
-- a computation that when executed blocks until the thread terminates
-- then returns the final value of the thread.
forkIOWithUnmask
:: ((forall b. IO b -> IO b) -> IO a) -> IO (ThreadId, IO (Result a))
forkIOWithUnmask = forkWithUnmask Control.Concurrent.forkIOWithUnmask
-- | Like @Control.Concurrent.'Control.Concurrent.forkOnWithUnmask'@ but returns
-- a computation that when executed blocks until the thread terminates
-- then returns the final value of the thread.
forkOnWithUnmask
:: Int -> ((forall b. IO b -> IO b) -> IO a) -> IO (ThreadId, IO (Result a))
forkOnWithUnmask = forkWithUnmask . Control.Concurrent.forkOnWithUnmask
--------------------------------------------------------------------------------
-- Utils
--------------------------------------------------------------------------------
fork :: (IO () -> IO ThreadId) -> (IO a -> IO (ThreadId, IO (Result a)))
fork doFork = \a -> do
res <- newEmptyMVar
tid <- mask $ \restore -> doFork $ try (restore a) >>= putMVar res
return (tid, readMVar res)
forkWithUnmask
:: (((forall b. IO b -> IO b) -> IO ()) -> IO ThreadId)
-> ((forall b. IO b -> IO b) -> IO a) -> IO (ThreadId, IO (Result a))
forkWithUnmask doForkWithUnmask = \f -> do
res <- newEmptyMVar
tid <- mask $ \restore ->
doForkWithUnmask $ \unmask ->
try (restore $ f unmask) >>= putMVar res
return (tid, readMVar res)
--------------------------------------------------------------------------------
-- Results
--------------------------------------------------------------------------------
-- | A result of a thread is either some exception that was thrown in the thread
-- and wasn't catched or the actual value that was returned by the thread.
type Result a = Either SomeException a
-- | Retrieve the actual value from the result.
--
-- When the result is 'SomeException' the exception is thrown.
result :: Result a -> IO a
result = either throwIO return
|