Proposal: add forkOnIO and friends to Control.Concurrent:

Simon Marlow marlowsd at
Wed Jan 5 11:51:31 CET 2011

On 24/12/2010 01:57, Thomas Schilling wrote:
> I agree with that a more descriptive type than Int would be better
> (even if it's just a newtype).

The Int argument has three purposes:

  - you can ask that two threads be placed on the same processor
    (to optimise for communication overhead)

  - you can ask that two threads be placed on different processors,
    if enough are available (to optimise for parallelism)

  - values are independent of the number of processors actually available

The third point is important, because the number of actual processors 
might change over time, so it's important that the scheduler knows what 
to do with pinned threads when it adds or removes processors.  This is 
why something like

  getCapabilities :: IO [Capability]

isn't good - it might give you different results depending on when you 
call it, and you have to make fixed scheduling decisions based on the 
number of processors at the current time.

if the Int were instead a newtype, it would at least need to be an 
instance of Enum, and I'm not sure there's any advantage in that.  Can 
you see any?

> I also find the name 'forkOnIO' extremely confusing.  Without reading
> the docs it seems to imply that a thread is created on IO, i.e., if
> I/O happens.  This makes no sense, and is of course not what's
> happening.  However, I assume you chose it because forkIOOn looks a
> bit weird.  In that case, why not use forkThreadOn, and in a separate
> proposal change forkIO to forkThread (or just fork).

How about just forkOn?  I agree that we should rename forkIO too, but 
let's leave that for another proposal.


> Other than that, I agree that the implementation seems likely portable
> (and can easily be made to work in single-threaded systems).
> On 22 December 2010 11:41, Simon Marlow<marlowsd at>  wrote:
>> Ticket:
>> I think these functions are implementation-independent enough to add to the
>> main `Control.Concurrent` API:
>> {{{
>> {- |
>> Like 'forkIO', but lets you specify on which CPU the thread is
>> created.  Unlike a `forkIO` thread, a thread created by `forkOnIO`
>> will stay on the same CPU for its entire lifetime (`forkIO` threads
>> can migrate between CPUs according to the scheduling policy).
>> `forkOnIO` is useful for overriding the scheduling policy when you
>> know in advance how best to distribute the threads.
>> The `Int` argument specifies the CPU number; it is interpreted modulo
>> the value returned by 'getNumCapabilities'.
>> -}
>> forkOnIO :: Int ->  IO () ->  IO ThreadId
>> -- | Like 'forkIOWithUnmask', but the child thread is pinned to the
>> -- given CPU, as with 'forkOnIO'.
>> forkOnIOWithUnmask :: Int ->  ((forall a . IO a ->  IO a) ->  IO ()) ->  IO
>> ThreadId
>> {- |
>> Returns the number of Haskell threads that can run truly
>> simultaneously (on separate physical processors) at any given time.
>> The CPU number passed to `forkOnIO` is interpreted modulo this
>> value.
>> An implementation in which Haskell threads are mapped directly to
>> OS threads might return the number of physical processor cores in
>> the machine, and 'forkOnIO' would be implemented using the OS's
>> affinity facilities.  An implementation that schedules Haskell
>> threads onto a smaller number of OS threads (like GHC) would return
>> the number of such OS threads that can be running simultaneously.
>> GHC notes: this returns the number passed as the argument to the
>> @+RTS -N@ flag.  In current implementations, the value is fixed
>> when the program starts and never changes, but it is possible that
>> in the future the number of capabilities might vary at runtime.
>> -}
>> getNumCapabilities :: IO Int
>> -- | returns @Just x@ if the given thread was created with either
>> -- @forkOnIO x@ or @forkOnIOWithUnmask@, or @Nothing@ otherwise.
>> threadIsPinned :: ThreadId ->  IO (Maybe Int)
>> }}}
>> In base (GHC 7.0.1) we currently have `forkOnIO` and
>> `forkOnIOUnmasked`, available from `GHC.Conc`.  I am about to add the other
>> functions to `GHC.Conc`, and deprecate `forkOnIOUnmasked` (see
>>  This proposal is to
>> export the above functions from`Control.Concurrent` too.
>> A feature request for `threadIsPinned` was submitted as
>> Naming is up for grabs: I'm not at all sure that "capabilities" is a good
>> word here, but I can't think of any better ideas.  "processors" or "CPUs"
>> don't seem quite right.
>> Discussion period: 4 weeks (until 19 Jan 2011)
>> Cheers,
>>         Simon
>> _______________________________________________
>> Libraries mailing list
>> Libraries at

More information about the Libraries mailing list