| Version 30 (modified by simonmar@…, 7 years ago) |
|---|
Concurrency
Proposals
These are proposals on which we are generally agreed so far, with brief rationale.
- Some kind of concurrency will be included in the spec, including MVars for communication.
At least the following interface will be provided:- Control.Concurrent.MVar - everything except addMVarFinalizer
- Control.Concurrent - ThreadId, myThreadId, forkIO, yield, sleep (replaces threadDelay).
- Control.Concurrent.Chan, Control.Concurrent.QSem, Control.Concurrent.QSemN, Control.Concurrent.SampleVar
- Concurrent foreign calls are required.
Rationale:- concurrent foreign calls are required to guarantee progress of other Haskell threads when one thread makes a blocking call.
- concurrent foreign calls are required for implementing I/O multiplexing, a principle use of concurrency.
- concurrent foreign calls are required to guarantee timely responsiveness of an interactive application in the presence of long-running foreign calls.
- Concurrent/reentrant foreign calls are required. Hence, the
Haskell system must be able to process call-ins from arbitrary
external OS threads.
Rationale:- the main loop of a GUI may block (hence concurrent) and makes callbacks (hence reentrant), we need to support this kind of usage.
- providing concurrent/reentrant foreign calls does not impose significant extra overhead on the rest of the system. For example, a call-in can check a thread-local variable (fast) to see whether it arose from a foreign call.
- Foreign calls will be able to specify independently whether they
are concurrent, reentrant, or both. (syntax and the sense of the annotations are still to be decided, see below).
Rationale:- these annotations can have a profound impact on performance in some implementations.
- Bound threads are not required, but allowed as an extension, and we will specify their meaning.
References
Documentation:
- The Control.Concurrency module
Papers and other docs:
- Concurrent Haskell (the original paper, including a semantics)
- Extending the Haskell FFI with Concurrency (a specification of the interaction between concurrency and the FFI, with a semantics)
- A Draft report addendum (a shorter version of the above paper).
- Software Transactional Memory
- State Threads for C
Old Stuff
What follows is old material, which we will probably want to incorporate into the main text later.
Progress Guarentee
- if any haskell thread is runnable then at least one thread will be running.
- foreign calls marked 'concurrent' will not interfere will the above rule.
Additionally, we have a fairness property of MVars:
- A thread blocked on an MVar will eventually run, provided there are no other threads holding the MVar indefinitely.
This means that MVar blocking must be implemented in a fair way, eg. a FIFO of blocked threads.
In order to meet the progress guarentee, an implementation must yield to another thread, waiting for an appropriate event, before any action that entails blocking for an indeterminate amount of time.
MVar Guarentees
initial proposal is here:
http://www.haskell.org//pipermail/haskell-prime/2006-March/001168.html
Alternate, simpler proposal: full memory barrier at every putMVar and takeMVar.
perhaps a better phrasing of the first proposal exists, in practice, from a users point of view, it would be hard to tell the difference between the two models, but we should say something concrete on the matter.
Misc library stuff
yield is guarenteed to choose an alternate thread if another one exists and is runnable.
sleep guarentees the thread will wait as long as its argument at a minimum. it may be blocked for longer.
I/O
I/O operations from System.IO, System.Directory, System.Process (and others?) do not prevent other threads from making progress when they are waiting for I/O to complete.
We could provide a lower-level non-blocking I/O interface along the lines of threadWaitRead, threadWaitWrite, perhaps in Control.Concurent.IO.
Optional extensions to basic standard
These are optional extensions a compiler may implement. In some implementations they may entail a run-time cost to non-concurrent code or a compiler might need a special option to enable them. However, A compiler is not required to provide more than one concurrency model as long as it can meet the requirements of the standard and any options it claims to support.
If a compiler documents that it supports one of the following options, then it must adhere to the rules of that option as well.
Optional Feature 1 - Preemption
The standard only requires a progress guarentee, that a thread is always running, making progress. If an implementation supports context switching during arbitrary computations and meets the stronger fairness guarentee below, then it can be said to support the 'Preemption' option.
Fairness Guarentee
- no starvation
new library calls provided
- mergeIO, nmergeIO
Optional Feature 2 - OS threads
The implementation additionally allows the following:
- foreign exported functions, and function pointers created by foreign import "wrapper", can be invoked from multiple OS threads
- bound threads: forkOS, isCurrentThreadBound, runInBoundThread, runInUnboundThread
- concurrent/reentrant foreign calls are supported
Notes
Sharing
Although not mentioned in the standard, the use of Concurrency may affect the lazy sharing of computations. Consult an implementations documentation if this might be an issue for you.
unsafePerformIO
Using concurrent operations inside of an unsafePerformIO or unsafeInterleaveIO may have unforseen consequences, check an implementations documentation for details before depending on any particular behavior.
Status of Compilers
standard concurrency: hugs, jhc(planned)
standard + preemptive: ghc, yhc
standard + preemptive + OS threads: "ghc -threaded"
