Movatterモバイル変換


[0]ホーム

URL:


base-4.12.0.0: Basic libraries

Copyright(c) The University of Glasgow 2001
LicenseBSD-style (see the file libraries/base/LICENSE)
Maintainerlibraries@haskell.org
Stabilityexperimental
Portabilitynon-portable (concurrency)
Safe HaskellTrustworthy
LanguageHaskell2010

Control.Concurrent

Contents

Description

A common interface to a collection of useful concurrency abstractions.

Synopsis

Concurrent Haskell

The concurrency extension for Haskell is described in the paperConcurrent Haskellhttp://www.haskell.org/ghc/docs/papers/concurrent-haskell.ps.gz.

Concurrency is "lightweight", which means that both thread creationand context switching overheads are extremely low. Scheduling ofHaskell threads is done internally in the Haskell runtime system, anddoesn't make use of any operating system-supplied thread packages.

However, if you want to interact with a foreign library that expects yourprogram to use the operating system-supplied thread package, you can do soby usingforkOS instead offorkIO.

Haskell threads can communicate viaMVars, a kind of synchronisedmutable variable (seeControl.Concurrent.MVar). Several commonconcurrency abstractions can be built fromMVars, and these areprovided by theControl.Concurrent library.In GHC, threads may also communicate via exceptions.

Basic concurrency operations

dataThreadIdSource#

AThreadId is an abstract type representing a handle to a thread.ThreadId is an instance ofEq,Ord andShow, wheretheOrd instance implements an arbitrary total ordering overThreadIds. TheShow instance lets you convert an arbitrary-valuedThreadId to string form; showing aThreadId value is occasionallyuseful when debugging or diagnosing the behaviour of a concurrentprogram.

Note: in GHC, if you have aThreadId, you essentially havea pointer to the thread itself. This means the thread itself can't begarbage collected until you drop theThreadId.This misfeature will hopefully be corrected at a later date.

Instances
EqThreadIdSource#

Since: 4.2.0.0

Instance details

Defined inGHC.Conc.Sync

OrdThreadIdSource#

Since: 4.2.0.0

Instance details

Defined inGHC.Conc.Sync

ShowThreadIdSource#

Since: 4.2.0.0

Instance details

Defined inGHC.Conc.Sync

myThreadId ::IOThreadIdSource#

Returns theThreadId of the calling thread (GHC only).

forkIO ::IO () ->IOThreadIdSource#

Creates a new thread to run theIO computation passed as thefirst argument, and returns theThreadId of the newly createdthread.

The new thread will be a lightweight,unbound thread. Foreign callsmade by this thread are not guaranteed to be made by any particular OSthread; if you need foreign calls to be made by a particular OSthread, then useforkOS instead.

The new thread inherits themasked state of the parent (seemask).

The newly created thread has an exception handler that discards theexceptionsBlockedIndefinitelyOnMVar,BlockedIndefinitelyOnSTM, andThreadKilled, and passes all other exceptions to the uncaughtexception handler.

forkFinally ::IO a -> (EitherSomeException a ->IO ()) ->IOThreadIdSource#

Fork a thread and call the supplied function when the thread is about to terminate, with an exception or a returned value. The function is called with asynchronous exceptions masked.

forkFinally action and_then =  mask $ \restore ->    forkIO $ try (restore action) >>= and_then

This function is useful for informing the parent when a child terminates, for example.

Since: 4.6.0.0

forkIOWithUnmask :: ((forall a.IO a ->IO a) ->IO ()) ->IOThreadIdSource#

LikeforkIO, but the child thread is passed a function that can be used to unmask asynchronous exceptions. This function is typically used in the following way

 ... mask_ $ forkIOWithUnmask $ \unmask ->                catch (unmask ...) handler

so that the exception handler in the child thread is established with asynchronous exceptions masked, meanwhile the main body of the child thread is executed in the unmasked state.

Note that the unmask function passed to the child thread should only be used in that thread; the behaviour is undefined if it is invoked in a different thread.

Since: 4.4.0.0

killThread ::ThreadId ->IO ()Source#

killThread raises theThreadKilled exception in the giventhread (GHC only).

killThread tid = throwTo tid ThreadKilled

throwTo ::Exception e =>ThreadId -> e ->IO ()Source#

throwTo raises an arbitrary exception in the target thread (GHC only).

Exception delivery synchronizes between the source and target thread:throwTo does not return until the exception has been raised in thetarget thread. The calling thread can thus be certain that the targetthread has received the exception. Exception delivery is also atomicwith respect to other exceptions. Atomicity is a useful property to havewhen dealing with race conditions: e.g. if there are two threads thatcan kill each other, it is guaranteed that only one of the threadswill get to kill the other.

Whatever work the target thread was doing when the exception wasraised is not lost: the computation is suspended until required byanother thread.

If the target thread is currently making a foreign call, then theexception will not be raised (and hencethrowTo will not return)until the call has completed. This is the case regardless of whetherthe call is inside amask or not. However, in GHC a foreign callcan be annotated asinterruptible, in which case athrowTo willcause the RTS to attempt to cause the call to return; see the GHCdocumentation for more details.

Important note: the behaviour ofthrowTo differs from that described inthe paper "Asynchronous exceptions in Haskell"(http://research.microsoft.com/~simonpj/Papers/asynch-exns.htm).In the paper,throwTo is non-blocking; but the library implementation adoptsa more synchronous design in whichthrowTo does not return until the exceptionis received by the target thread. The trade-off is discussed in Section 9 of the paper.Like any blocking operation,throwTo is therefore interruptible (see Section 5.3 ofthe paper). Unlike other interruptible operations, however,throwToisalways interruptible, even if it does not actually block.

There is no guarantee that the exception will be delivered promptly,although the runtime will endeavour to ensure that arbitrarydelays don't occur. In GHC, an exception can only be raised when athread reaches asafe point, where a safe point is where memoryallocation occurs. Some loops do not perform any memory allocationinside the loop and therefore cannot be interrupted by athrowTo.

If the target ofthrowTo is the calling thread, then the behaviouris the same asthrowIO, except that the exceptionis thrown as an asynchronous exception. This means that if there isan enclosing pure computation, which would be the case if the currentIO operation is insideunsafePerformIO orunsafeInterleaveIO, thatcomputation is not permanently replaced by the exception, but issuspended as if it had received an asynchronous exception.

Note that ifthrowTo is called with the current thread as thetarget, the exception will be thrown even if the thread is currentlyinsidemask oruninterruptibleMask.

Threads with affinity

forkOn ::Int ->IO () ->IOThreadIdSource#

LikeforkIO, but lets you specify on which capability the threadshould run. Unlike aforkIO thread, a thread created byforkOnwill stay on the same capability for its entire lifetime (forkIOthreads can migrate between capabilities according to the schedulingpolicy).forkOn is useful for overriding the scheduling policy whenyou know in advance how best to distribute the threads.

TheInt argument specifies acapability number (seegetNumCapabilities). Typically capabilities correspond to physicalprocessors, but the exact behaviour is implementation-dependent. Thevalue passed toforkOn is interpreted modulo the total number ofcapabilities as returned bygetNumCapabilities.

GHC note: the number of capabilities is specified by the+RTS -Noption when the program is started. Capabilities can be fixed toactual processor cores with+RTS -qa if the underlying operatingsystem supports that, although in practice this is usually unnecessary(and may actually degrade performance in some cases - experimentationis recommended).

Since: 4.4.0.0

forkOnWithUnmask ::Int -> ((forall a.IO a ->IO a) ->IO ()) ->IOThreadIdSource#

LikeforkIOWithUnmask, but the child thread is pinned to the given CPU, as withforkOn.

Since: 4.4.0.0

getNumCapabilities ::IOIntSource#

Returns the number of Haskell threads that can run trulysimultaneously (on separate physical processors) at any given time. To changethis value, usesetNumCapabilities.

Since: 4.4.0.0

setNumCapabilities ::Int ->IO ()Source#

Set the number of Haskell threads that can run truly simultaneously(on separate physical processors) at any given time. The numberpassed toforkOn is interpreted modulo this value. The initialvalue is given by the+RTS -N runtime flag.

This is also the number of threads that will participate in parallelgarbage collection. It is strongly recommended that the number ofcapabilities is not set larger than the number of physical processorcores, and it may often be beneficial to leave one or more cores freeto avoid contention with other processes in the machine.

Since: 4.5.0.0

threadCapability ::ThreadId ->IO (Int,Bool)Source#

Returns the number of the capability on which the thread is currently running, and a boolean indicating whether the thread is locked to that capability or not. A thread is locked to a capability if it was created withforkOn.

Since: 4.4.0.0

Scheduling

Scheduling may be either pre-emptive or co-operative, depending on the implementation of Concurrent Haskell (see below 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:

  main = forkIO (write 'a') >> write 'b'    where write c = putChar c >> write c

will print eitheraaaaaaaaaaaaaa... orbbbbbbbbbbbb..., instead of some random interleaving ofas andbs. In practice, cooperative multitasking is sufficient for writing simple graphical user interfaces.

yield ::IO ()Source#

Theyield action allows (forces, in a co-operative multitasking implementation) a context-switch to any other currently runnable threads (if any), and is occasionally useful when implementing concurrency abstractions.

Blocking

Different Haskell implementations have different characteristics withregard to which operations blockall threads.

Using GHC without the-threaded option, all foreign calls will blockall other Haskell threads in the system, although I/O operations willnot. With the-threaded option, only foreign calls with theunsafeattribute will block all other threads.

Waiting

threadDelay ::Int ->IO ()Source#

Suspends the current thread for a given number of microseconds (GHC only).

There is no guarantee that the thread will be rescheduled promptly when the delay has expired, but the thread will never continue to runearlier than specified.

threadWaitRead ::Fd ->IO ()Source#

Block the current thread until data is available to read on the given file descriptor (GHC only).

This will throw anIOError if the file descriptor was closed while this thread was blocked. To safely close a file descriptor that has been used withthreadWaitRead, usecloseFdWith.

threadWaitWrite ::Fd ->IO ()Source#

Block the current thread until data can be written to the given file descriptor (GHC only).

This will throw anIOError if the file descriptor was closed while this thread was blocked. To safely close a file descriptor that has been used withthreadWaitWrite, usecloseFdWith.

threadWaitReadSTM ::Fd ->IO (STM (),IO ())Source#

Returns an STM action that can be used to wait for data to read from a file descriptor. The second returned value is an IO action that can be used to deregister interest in the file descriptor.

Since: 4.7.0.0

threadWaitWriteSTM ::Fd ->IO (STM (),IO ())Source#

Returns an STM action that can be used to wait until data can be written to a file descriptor. The second returned value is an IO action that can be used to deregister interest in the file descriptor.

Since: 4.7.0.0

Communication abstractions

moduleControl.Concurrent.MVar

moduleControl.Concurrent.Chan

moduleControl.Concurrent.QSem

moduleControl.Concurrent.QSemN

Bound Threads

Support for multiple operating system threads and bound threads as describedbelow 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.

A bound thread is a haskell thread that isbound to an operating systemthread. While the bound thread is still scheduled by the Haskell run-timesystem, the operating system thread takes care of all the foreign calls madeby the bound thread.

To a foreign library, the bound thread will look exactly like an ordinaryoperating system thread created using OS functions likepthread_createorCreateThread.

Bound threads can be created using theforkOS function below. All foreignexported functions are run in a bound thread (bound to the OS thread thatcalled the function). Also, themain action of every Haskell program isrun in a bound thread.

Why do we need this? Because if a foreign library is called from a threadcreated usingforkIO, it won't have access to anythread-local state -state variables that have specific values for each OS thread(see POSIX'spthread_key_create or Win32'sTlsAlloc). Therefore, somelibraries (OpenGL, for example) will not work from a thread created usingforkIO. They work fine in threads created usingforkOS or when calledfrommain or from aforeign export.

In terms of performance,forkOS (aka bound) threads are much moreexpensive thanforkIO (aka unbound) threads, because aforkOSthread is tied to a particular OS thread, whereas aforkIO threadcan be run by any OS thread. Context-switching between aforkOSthread and aforkIO thread is many times more expensive than betweentwoforkIO threads.

Note in particular that the main program thread (the thread runningMain.main) is always a bound thread, so for good concurrencyperformance you should ensure that the main thread is not doingrepeated communication with other threads in the system. Typicallythis means forking subthreads to do the work usingforkIO, andwaiting for the results in the main thread.

rtsSupportsBoundThreads ::BoolSource#

True if bound threads are supported. IfrtsSupportsBoundThreads isFalse,isCurrentThreadBound will always returnFalse and bothforkOS andrunInBoundThread will fail.

forkOS ::IO () ->IOThreadIdSource#

LikeforkIO, this sparks off a new thread to run theIOcomputation passed as the first argument, and returns theThreadIdof the newly created thread.

However,forkOS creates abound thread, which is necessary if youneed to call foreign (non-Haskell) libraries that make use ofthread-local state, such as OpenGL (seeControl.Concurrent).

UsingforkOS instead offorkIO makes no difference at all to thescheduling behaviour of the Haskell runtime system. It is a commonmisconception that you need to useforkOS instead offorkIO toavoid blocking all the Haskell threads when making a foreign call;this isn't the case. To allow foreign calls to be made withoutblocking all the Haskell threads (with GHC), it is only necessary touse the-threaded option when linking your program, and to make surethe foreign import is not markedunsafe.

forkOSWithUnmask :: ((forall a.IO a ->IO a) ->IO ()) ->IOThreadIdSource#

LikeforkIOWithUnmask, but the child thread is a bound thread, as withforkOS.

isCurrentThreadBound ::IOBoolSource#

ReturnsTrue if the calling thread isbound, that is, if it is safe to use foreign libraries that rely on thread-local state from the calling thread.

runInBoundThread ::IO a ->IO aSource#

Run theIO computation passed as the first argument. If the calling threadis notbound, a bound thread is created temporarily.runInBoundThreaddoesn't finish until theIO computation finishes.

You can wrap a series of foreign function calls that rely on thread-local statewithrunInBoundThread so that you can use them without knowing whether thecurrent thread isbound.

runInUnboundThread ::IO a ->IO aSource#

Run theIO computation passed as the first argument. If the calling threadisbound, an unbound thread is created temporarily usingforkIO.runInBoundThread doesn't finish until theIO computation finishes.

Use this functiononly in the rare case that you have actually observed aperformance loss due to the use of bound threads. A program thatdoesn't need its main thread to be bound and makesheavy use of concurrency(e.g. a web server), might want to wrap itsmain action inrunInUnboundThread.

Note that exceptions which are thrown to the current thread are thrown in turnto the thread that is executing the given computation. This ensures there'salways a way of killing the forked thread.

Weak references to ThreadIds

mkWeakThreadId ::ThreadId ->IO (WeakThreadId)Source#

Make a weak pointer to aThreadId. It can be important to do this if you want to hold a reference to aThreadId while still allowing the thread to receive theBlockedIndefinitely family of exceptions (e.g.BlockedIndefinitelyOnMVar). Holding a normalThreadId reference will prevent the delivery ofBlockedIndefinitely exceptions because the reference could be used as the target ofthrowTo at any time, which would unblock the thread.

Holding aWeak ThreadId, on the other hand, will not prevent the thread from receivingBlockedIndefinitely exceptions. It is still possible to throw an exception to aWeak ThreadId, but the caller must usedeRefWeak first to determine whether the thread still exists.

Since: 4.6.0.0

GHC's implementation of concurrency

This section describes features specific to GHC's implementation of Concurrent Haskell.

Haskell threads and Operating System threads

In GHC, threads created byforkIO are lightweight threads, and are managed entirely by the GHC runtime. Typically Haskell threads are an order of magnitude or two more efficient (in terms of both time and space) than operating system threads.

The downside of having lightweight threads is that only one can run at a time, so if one thread blocks in a foreign call, for example, the other threads cannot continue. The GHC runtime works around this by making use of full OS threads where necessary. When the program is built with the-threaded option (to link against the multithreaded version of the runtime), a thread making asafe foreign call will not block the other threads in the system; another OS thread will take over running Haskell threads until the original call returns. The runtime maintains a pool of theseworker threads so that multiple Haskell threads can be involved in external calls simultaneously.

TheSystem.IO library manages multiplexing in its own way. On Windows systems it usessafe foreign calls to ensure that threads doing I/O operations don't block the whole runtime, whereas on Unix systems all the currently blocked I/O requests are managed by a single thread (theIO manager thread) using a mechanism such asepoll orkqueue, depending on what is provided by the host operating system.

The runtime will run a Haskell thread using any of the available worker OS threads. If you need control over which particular OS thread is used to run a given Haskell thread, perhaps because you need to call a foreign library that uses OS-thread-local state, then you need bound threads (seeControl.Concurrent).

If you don't use the-threaded option, then the runtime does not make use of multiple OS threads. Foreign calls will block all other running Haskell threads until the call returns. TheSystem.IO library still does multiplexing, so there can be multiple threads doing I/O, and this is handled internally by the runtime usingselect.

Terminating the program

In a standalone GHC program, only the main thread is required to terminate in order for the process to terminate. Thus all other forked threads will simply terminate at the same time as the main thread (the terminology for this kind of behaviour is "daemonic threads").

If you want the program to wait for child threads to finish before exiting, you need to program this yourself. A simple mechanism is to have each child thread write to anMVar when it completes, and have the main thread wait on all theMVars before exiting:

  myForkIO :: IO () -> IO (MVar ())  myForkIO io = do    mvar <- newEmptyMVar    forkFinally io (\_ -> putMVar mvar ())    return mvar

Note that we useforkFinally to make sure that theMVar is written to even if the thread dies or is killed for some reason.

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     cs <- takeMVar children     case cs of       []   -> return ()       m:ms -> do          putMVar children ms          takeMVar m          waitForChildren   forkChild :: IO () -> IO ThreadId   forkChild io = do       mvar <- newEmptyMVar       childs <- takeMVar children       putMVar children (mvar:childs)       forkFinally io (\_ -> putMVar mvar ())    main =      later waitForChildren $      ...

The main thread principle also applies to calls to Haskell from outside, usingforeign export. When theforeign exported function is invoked, it starts a new main thread, and it returns when this main thread terminates. If the call causes new threads to be forked, they may remain in the system after theforeign exported function has returned.

Pre-emption

GHC implements pre-emptive multitasking: the execution of threads are interleaved in a random fashion. More specifically, 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 pathological benchmark-style code, however).

The rescheduling timer runs on a 20ms granularity by default, but this may be altered using the-i<n> RTS option. After a rescheduling "tick" the running thread is pre-empted as soon as possible.

One final note: theaaaabbbb example may not work too well on GHC (see Scheduling, above), due to the locking on aHandle. Only one thread may hold the lock on aHandle at any one time, so if a reschedule happens while a thread is holding the lock, the other thread won't be able to run. The upshot is that the switch fromaaaa tobbbbb happens infrequently. It can be improved by lowering the reschedule tick period. We also have a patch that causes a reschedule whenever a thread waiting on a lock is woken up, but haven't found it to be useful for anything other than this example :-)

Deadlock

GHC attempts to detect when threads are deadlocked using the garbagecollector. A thread that is not reachable (cannot be found byfollowing pointers from live objects) must be deadlocked, and in thiscase the thread is sent an exception. The exception is eitherBlockedIndefinitelyOnMVar,BlockedIndefinitelyOnSTM,NonTermination, orDeadlock, depending on the way in which thethread is deadlocked.

Note that this feature is intended for debugging, and should not berelied on for the correct operation of your program. There is noguarantee that the garbage collector will be accurate enough to detectyour deadlock, and no guarantee that the garbage collector will run ina timely enough manner. Basically, the same caveats as for finalizersapply to deadlock detection.

There is a subtle interaction between deadlock detection andfinalizers (as created bynewForeignPtr or thefunctions inSystem.Mem.Weak): if a thread is blocked waiting for afinalizer to run, then the thread will be considered deadlocked andsent an exception. So preferably don't do this, but if you have noalternative then it is possible to prevent the thread from beingconsidered deadlocked by making aStablePtr pointing to it. Don'tforget to release theStablePtr later withfreeStablePtr.

Produced byHaddock version 2.20.0


[8]ページ先頭

©2009-2025 Movatter.jp