5

私はこの単純なコードを持っています:(私はlinqpadで実行します

void Main()
{
    for ( int  i=0;i<10;i++)
     {
      int  tmp=i;
      new Thread (() =>doWork(tmp)).Start();
     }
}

 public void doWork( int h)
 {
 h.Dump();
 }

このint tmp=i;行はキャプチャ変数用です。したがって、各反復には独自の値があります。

2つの問題:

1)スレッドの実行が!であるのに対し、番号は連続していません。

2)時々私は10未満の数字を取得します!

ここにいくつかの実行出力があります:

ここに画像の説明を入力してくださいここに画像の説明を入力してくださいここに画像の説明を入力してくださいここに画像の説明を入力してください

質問

1)ケース1が発生している理由と、それを解決するにはどうすればよいですか?

2)ケース2が発生している理由と、それを解決するにはどうすればよいですか?

4

6 に答える 6

8

それらが連続していると期待すべきではありません。カーネルが選択すると、各スレッドが優先されます。純粋にそれぞれが開始されたときの性質によって、それらが連続して見える場合がありますが、それは純粋なチャンスです。

それらがすべて完了することを保証するために-IsBackground = false実行可能ファイルを存続させるために、新しい各スレッドをとしてマークします。例えば:

new Thread(() => doWork(tmp)) { IsBackground = false }.Start();
于 2012-05-31T11:33:57.827 に答える
2

スレッドは予測できない順序で実行され、メインスレッドが他のスレッドよりも先に終了した場合、すべての番号を取得することはできません(dump()は実行されません)。スレッドをIsBackground=falseとしてマークすると、すべてのスレッドが取得されます。スレッドを使用しない(またはスレッドを結合する、これは実際には同じことです)ことを除いて、最初の解決策の実際の解決策はありません。

于 2012-05-31T11:35:51.360 に答える
2

スレッド間の順序付けを期待するべきではありません。

新しいスレッドを開始すると、それはオペレーティングシステムの管理構造に追加されるだけです。最終的に、スレッドスケジューラがやって来て、スレッドにタイムスライスを割り当てます。これはラウンドロビン方式で実行され、ランダムなものを選択し、いくつかのヒューリスティックを使用して、どれが最も重要に見えるか(たとえば、フォアグラウンドにあるウィンドウを所有しているもの)を決定します。

出力の順序が関連している場合は、後で並べ替えるか、作業が始まる前の順序がわかっている場合は、各スレッドに結果を書き込むインデックスが指定されている配列を使用できます。

あなたの例のように新しいスレッドを作成することも非常に遅いです。マイクロタスクの場合、スレッドプールの使用は少なくとも1桁高速です。

于 2012-05-31T11:38:06.410 に答える
1

スレッド管理の性質はランダムです。両方のタスクを解決できますが、オーバーヘッドが大きすぎます。

  1. コンソール(またはダンプに使用するスレッド)で複数のスレッドが一致するという問題が発生します。同期メカニズムのオーバーライドは可能ですが複雑であり、パフォーマンスの低下を引き起こします
  2. すべてのスレッドが呼び出される前に終了します(@Marc Gravellによる回答を参照)
于 2012-05-31T11:38:04.953 に答える
0

順序付けが重要な場合は、共有キューを利用し、セマフォを使用して、一度に1つのスレッドのみがキューの先頭で動作するようにすることができます。

于 2012-05-31T12:12:54.463 に答える
0

スレッドの実行を注文することはできますが、特定の解決策の特定の問題については、ユーザーが特別に実行する必要があります。

例:スレッド1、2、3でコードのフェーズ1を完了してから、ID(割り当てたID)の順に次のフェーズに進みます。

セマフォを使用して、動作を実現できます。ブロックの同期と相互排除を検索し、テストアンドセット方式を使用します。

于 2015-03-02T03:02:19.787 に答える