Bound Threads

Daan Leijen daanleijen at
Fri Mar 14 12:55:49 EST 2003

Hi Wolfgang,

>> Maybe, the forkOS/forkIO approach is flawed, but I think we should
>> only rule it out when we can provide a convincing example where only
>> the keyword approach would work, and where we can't use combinators to
>> achieve the same effect.
> That's unfair ;-) --- I could also claim the reverse and say that we  stick with threadsafe/bound until we have a convincing example...
> Using combinators sounds good, but there are things where combinators  are not automatically the best choice (we're usually not using  combinators to implement lazyness, either), and we don't know yet  whether this is the case here or not. So let's just get on with the  discussion....

No, it is not unfair. We should only introduce a new keyword/syntax if we are unable
to express the behaviour in plain Haskell or if it very awkward to do so.

Now, I can be easily convinced that "threadsafe" is the way to go, whenever there
is a compelling example where forkOS/forkIO fails.

At first, I thought that one could never come up with a counter example: since
forkOS/forkIO are the most primitive calls, we can always model any strategy
implemented in C (and more).

However, I just realised that there is more than meets the eye: you just described
that "GHC moves all non-bound Haskell threads to a second OS thread". This is something that can not be described without adding another primitive (forkUnbound?)
and it may lead to an example that is not expressible with forkOS/forkIO.

On the other hand, it seems awkward/impossible to make sure that certain functions
are always called from a specific OS thread with the "threadsafe" approach while
the forkOS/forkIO primitives are always available to the programmer for explicit
management of threads.

In general though, I have learned over the years that is most of the time better
to first find an implementation using low-level primitives in Haskell, and maybe
later add special syntax, than to implement a strategy directly in C.

>> About the example:
>> [snip]
>> That is amazing :-) [...]
> [snip]
> makes  sure that there is a second OS thread available (some overhead the  first time) and b) makes sure that all non-bound [in the current  implementation: all] Haskell threads are executed by the second OS  thread from now on.
> [snip]

Thanks for the explanation. Just on the side, it seems that this approach always involves
an OS context switch for bound callbacks. This doesn't happen with the forkOS/forkIO approach.
It may be rather expensive, take a mouse motion event handler for example.

> Maybe we need a more exact specification of how forkOS/forkIO should  behave, especially with respect to foreign calls blocking other  threads. Could you elaborate on how you would expect "normal" (safe)  > foreign calls to behave in different situations?

1) "forkOS" starts a new haskell thread in a new OS thread
2) "forkIO" starts a new haskell thread in the current OS thread
3) maybe we should also add "forkUnbound" that forks a haskell thread that can automatically
   be moved between OS threads.
4) a foreign call blocks all haskell threads that are attached to the current OS thread
   until a) the call returns, or b) the call enters Haskell again.
5) on top of this, we can implement *) a library function "fork" that forks a new haskell thread
      that maybe runs in separate OS thread, depending on the architecture.
   *) a "threadSafe" combinator to make non-blocking foreign calls.

* "forkOS" doesn't have to use a new OS thread to run Haskell threads, just when calling
   a foreign function, so it would work on Hugs too for example. (as explained in a previous mail).
* The naming is a bit inconveniently chosen. Better would be:
   forkOS => forkNativeThread  forkIO => forkHaskellThread
  Now, "forkIO" can now be implemented in terms of those two functions, and can
  be used when the user doesn't care about how the thread is scheduled.

Now, what I don't like about my proposal and your proposal is that the user has to be aware of OS threads when making foreign calls by wrapping it in "threadSafe" or
adding "threadsafe" sometimes -- but maybe that is unavoidable.

All the best,

More information about the FFI mailing list