6

私は次のコードを持っています:

import Control.Concurrent

sleepSort = mapM_ (forkIO . put)
  where put x = threadDelay (x*10000) >> print x

これは、整数のセットに対してスリープソートを実行し、1つの警告を除けば、正常に機能します。

プログラムは、データセット内の各番号を想定どおりに順番に出力します。ただし、最後の番号の印刷が終了すると、ユーザーが番号を入力するのを待ってから、その番号をエコーバックして完了します。

私はどの時点でもユーザー入力を求めているとは思わないのに、なぜこれが起こっているのですか?

4

1 に答える 1

7

これは、メインスレッドが他のスレッドの完了を待機しないために発生します。プログラムはnスレッドを開始しますが、メインスレッドはすぐに終了し、インタプリタプロンプトに戻ります。その間、他のスレッドは出力を生成し続けます。

Prelude Control.Concurrent> sleepSort [1,2,3]
1
Prelude Control.Concurrent> 2
3

これを修正するには、メインスレッドに遅延を追加します。

Prelude Control.Concurrent> sleepSort [1,2,3] >> threadDelay 10000
1
2
3

コンパイルされたプログラムを実行している場合は、何も出力せずにすぐに終了します。

$ cat Test.hs
import Control.Concurrent

sleepSort = mapM_ (forkIO . put)
  where put x = threadDelay (x*1000) >> print x

main = sleepSort [1,2,3]
$ ghc --make -O2 Test.hs
[1 of 1] Compiling Main             ( Test.hs, Test.o )
Linking Test ...
$ ./Test
$

更新:threadDelayへの呼び出しを追加する代わりに、関数mainでセマフォを使用できます。sleepSort

import Control.Concurrent
import Control.Concurrent.QSemN

sleepSort l = do
  qsem <- newQSemN 0
  mapM_ (forkIO . put qsem) l
  waitQSemN qsem n
  where
    n = length l
    put qsem x = threadDelay (x*1000) >> print x >> signalQSemN qsem 1

main = sleepSort [1,2,3]
于 2012-08-24T22:35:48.250 に答える