[Haskell-beginners] Why does forkIO also create native threads?

Peter Verswyvelen bugfact at gmail.com
Mon Apr 13 14:35:33 EDT 2009

It seems that it's not the forkIO that is creating native threads (using GHC
6.10.1, -O flag)
For example, the following code only has 5 threads on my Windows box, while
I fork 10 lightweight threads

import System.IO
import Control.Concurrent
import Control.Monad

entry :: Char -> IO()
entry c  = do
  forever $ putChar c
main = do
hSetBuffering stdout NoBuffering
mapM_ (forkIO . entry) ['0'..'9']
putStrLn "all forked; press ENTER to quit"
However, things can get bizarre. When we change the entry function into

entry :: Char -> IO()
entry c  = do
  putChar c
  threadDelay maxBound

Then on my machine 13 native threads *are* created. This might make sense
because its waiting forever, but native threads are also created for the
following code:

entry :: Char -> IO()
entry c  = do
  putChar c
  forever $ threadDelay 0

This feels like overkill, so it seems threadDelay always forks a new native
thread, although this is not documented.

We can also get into the dark corners of GHC's lightweight thread
scheduling: a thread switch only happens when memory is allocated on the GC
head (but this is documented in the API)

So the following code will not work, the runtime seems to get stuck in an
infinite loop after the first thread is created.

entry :: Char -> IO()
entry c  = do
  putChar c
  forever $ return ()

In artificial cases like this you can use yield

entry :: Char -> IO()
entry c  = do
  putChar c
  forever yield

On Mon, Apr 13, 2009 at 10:37 AM, Lych <lych77 at gmail.com> wrote:

> I wrote a simple ECHO server like this:
> ----------------------------------------------------
> import Network
> import System.IO
> import Control.Concurrent
> service cs = do
>        ln <- hGetContents cs
>        hPutStr cs ln
>        service cs
> acceptloop ls = do
>     (cs, host, port) <- accept ls
>     hSetBuffering cs LineBuffering
>     forkIO (service cs)
>     acceptloop ls
> main = do
>     ls <- listenOn (PortNumber 10061)
>     acceptloop ls
> ----------------------------------------------------
> And tested it with a client that initiates as many parallel
> connections as possible. The number of connections can just reach to
> 1000+ on my machine, but I thought it should be more, since forkIO
> generates lightweight threads. I also examined the number of threads
> in this process with some tool and it proved there was one native
> thread per connection. When I replaced the 'forkIO' in the program
> with 'forkOS', I got an exactly similar result. Have I thought
> something wrong about forkIO?
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/beginners/attachments/20090413/12b5b9ba/attachment.htm

More information about the Beginners mailing list