2011-07-04 17 views
2

私はまだマルチスレッドでの初心者です((1)例えば、スリープのために避ける)、そう私と一緒に負担してください。どのように私は正しくワーカースレッドを設計するのですか?

私は現在、グリッド上でいくつかのFVM計算を行うアプリケーションを書いています。時間明示的なモデルなので、タイムステップごとにグリッド全体の新しい値を計算する必要があります。私の考えは、この計算を4つのワーカースレッドに分配し、グリッドのセル(最初のスレッドは0,4,8を計算... 2番目のスレッド1,5,9 ...など)を処理することでした。

私はこれら4つのスレッドをプログラムの開始時に作成します。

彼らはこのような何かを見て:。

void __fastcall TCalculationThread::Execute() 
{ 
    bool alive = true; 
    THREAD_SIGNAL ts; 
    while (alive) 
    { 
     Sleep(1); 
     if (TryEnterCriticalSection(&TMS)) 
     { 
     ts = thread_signal; 
     LeaveCriticalSection(&TMS); 
     alive = !ts.kill; 
     if (ts.go && !ts.done.at(this->index)) 
     { 
      double delta_t = ts.dt; 
      for (unsigned int i=this->index; i < cells.size(); i+= this->steps) 
      { 
        calculate_one_cell(); 
      } 
      EnterCriticalSection(&TMS); 
       thread_signal.done.at(this->index)=true; 
      LeaveCriticalSection(&TMS); 
     } 
    } 
} 

彼らは労働者が起動する必要があるとき(メインスレッドセットがtrueにts.goメインスレッドと通信するために、グローバルな構造体を使用し

今私はこれを行う方法ではないと確信しています!それは間違っているだけでなく、それもうまく行かない...

私はセマフォやイベントがうまくいくことを、例えばhereで読んでいます。 this guy's questionに関するお問い合わせロックレスキュー

私はこれらの概念に精通していません。 あなたはこれをより良くするための方法を整理できますか?

はあなたの時間をありがとうございました。 (そしてフォーマットにごめんなさい)

私は、Borland C++ビルダーとそのスレッドオブジェクト(TThread)を使用しています。

+2

なぜ「スリープ」を呼びますか? –

+0

@David:多分スレッド時間を生むために! 'Sleep(0)'はまったく同じ結果を得るためによく使用されます。 – 0xC0000022L

+1

ちょっと - 誰かが私の古い記事を読む!私はそれだけでアップアップすることができますが、それは少し自助しています。 –

答えて

2

確かにより効果的なアルゴリズムは、あるスレッドでは0,1,2,3、他のスレッドでは4,5,6,7の歩留まりを計算することです。そのようなインターリーブメモリアクセスは非常に悪い変数は完全に独立しています。間違った共有の問題が発生します。これは、すべての書き込みのCPUロックに相当します。

+0

この寄付ありがとう、私はそれを変更し、それが顕著な違いを作るかどうかを確認します。 –

2

計算スレッドでSleep(1)を呼び出すことは、問題の良い解決策にはなりません。あなたのスレッドは、正当な理由でブロックするのではなく、有用な作業をしたいと思っています。

私はあなたの基本的な問題は、この基本的な形のシリアルアルゴリズムとして表現することができると思う:あなたはCalculate()に呼び出しを幸せ位置にある

for (int i=0; i<N; i++) 
    cells[i]->Calculate(); 

は、それぞれ独立しているあなたがここに持っている他、何Aであります平行にする。これは、これをmutexなしで実装できることを意味します。

これを達成するさまざまな方法があります。 OpenMPは1になります。スレッドプールクラスanother。独自のスレッドベースのソリューションをロールバックする場合は、共有変数にInterlockedIncrement()を使用して配列を反復処理します。

@DeadMGが示唆しているように、間違った共有の問題が発生する可能性がありますが、そうではない可能性があります。あなたが偽の共有をしているならば、さらに別のアプローチはより大きなサブアレイを横切ることです。本質的には、InterlockedIncrement()に渡されたインクリメント(すなわちストライド)は1より大きくなります。

結論は、コードを高速化する方法は、クリティカルセクション(したがって競合するセクション)とSleep(1)の両方を削除することです。

+0

あなたの答えに感謝します。私はInterlockedIncrement()を見ていきます。しかし、私はそれを理解すると、ワーカースレッドが負荷をより良く共有できるようになります。それは私に睡眠(1)とそのループを取り除く方法を私には明らかではありません。 InterlockedIncrement()は私の労働者とより効率的にコミュニケーションするのにどのように役立つのですか? –

+0

ロックを使用せずにすべてのセルを反復処理できます。 –

関連する問題