import Control.Exception as Exception
#ifdef __GLASGOW_HASKELL__
-import GHC.Conc
+import GHC.Conc ( ThreadId(..), myThreadId, killThread, yield,
+ threadDelay, threadWaitRead, threadWaitWrite )
import GHC.TopHandler ( reportStackOverflow, reportError )
import GHC.IOBase ( IO(..) )
import GHC.IOBase ( unsafeInterleaveIO )
-import GHC.IOBase ( newIORef, readIORef, writeIORef )
+import GHC.IOBase ( newIORef, readIORef, writeIORef )
import GHC.Base
import Foreign.StablePtr
Scheduling may be either pre-emptive or co-operative,
depending on the implementation of Concurrent Haskell (see below
- for imformation related to specific compilers). In a co-operative
+ for information related to specific compilers). In a co-operative
system, context switches only occur when you use one of the
primitives defined in this module. This means that programs such
as:
case ex of
-- ignore thread GC and killThread exceptions:
BlockedOnDeadMVar -> return ()
+ BlockedIndefinitely -> return ()
AsyncException ThreadKilled -> return ()
-- report all others:
- AsyncException StackOverflow -> reportStackOverflow False
- other -> reportError False other
+ AsyncException StackOverflow -> reportStackOverflow
+ other -> reportError other
#endif /* __GLASGOW_HASKELL__ */
{- $boundthreads
Support for multiple operating system threads and bound threads as described
-below is currently only available in the GHC runtime system when the runtime system
-has been compiled using a special option.
-
-When recompiling GHC, use .\/configure --enable-threaded-rts to enable this.
-To find your GHC has already been compiled that way, use
-'rtsSupportsBoundThreads' from GHCi.
+below is currently only available in the GHC runtime system if you use the
+/-threaded/ option when linking.
Other Haskell systems do not currently support multiple operating system threads.
foreign import ccall forkOS_createThread
:: StablePtr (IO ()) -> IO CInt
+failNonThreaded = fail $ "RTS doesn't support multiple OS threads "
+ ++"(use ghc -threaded when linking)"
+
forkOS action
| rtsSupportsBoundThreads = do
mv <- newEmptyMVar
tid <- takeMVar mv
freeStablePtr entry
return tid
- | otherwise = fail "RTS not built to support multiple OS threads."
+ | otherwise = failNonThreaded
-- | Returns 'True' if the calling thread is /bound/, that is, if it is
-- safe to use foreign libraries that rely on thread-local state from the
case resultOrException of
Left exception -> Exception.throw exception
Right result -> return result
- | otherwise = fail "RTS not built to support multiple OS threads."
+ | otherwise = failNonThreaded
{- |
Run the 'IO' computation passed as the first argument. If the calling thread
> myForkIO :: IO () -> IO (MVar ())
> myForkIO io = do
-> mvar \<- newEmptyMVar
-> forkIO (io \`finally\` putMVar mvar ())
+> mvar <- newEmptyMVar
+> forkIO (io `finally` putMVar mvar ())
> return mvar
Note that we use 'finally' from the
A better method is to keep a global list of all child
threads which we should wait for at the end of the program:
-> children :: MVar [MVar ()]
-> children = unsafePerformIO (newMVar [])
->
-> waitForChildren :: IO ()
-> waitForChildren = do
-> (mvar:mvars) \<- takeMVar children
-> putMVar children mvars
-> takeMVar mvar
-> waitForChildren
->
-> forkChild :: IO () -> IO ()
-> forkChild io = do
-> mvar \<- newEmptyMVar
-> forkIO (p \`finally\` putMVar mvar ())
-> childs \<- takeMVar children
-> putMVar children (mvar:childs)
->
-> later = flip finally
->
+> children :: MVar [MVar ()]
+> children = unsafePerformIO (newMVar [])
+>
+> waitForChildren :: IO ()
+> waitForChildren = do
+> cs <- takeMVar children
+> case cs of
+> [] -> return ()
+> m:ms -> do
+> putMVar children ms
+> takeMVar m
+> waitForChildren
+>
+> forkChild :: IO () -> IO ()
+> forkChild io = do
+> mvar <- newEmptyMVar
+> childs <- takeMVar children
+> putMVar children (mvar:childs)
+> forkIO (io `finally` putMVar mvar ())
+>
> main =
> later waitForChildren $
> ...
a thread may be pre-empted whenever it allocates some memory,
which unfortunately means that tight loops which do no
allocation tend to lock out other threads (this only seems to
- happen with pathalogical benchmark-style code, however).
+ happen with pathological benchmark-style code, however).
The rescheduling timer runs on a 20ms granularity by
default, but this may be altered using the