0

glibc pthreads ライブラリを使用してマルチスレッド アプリケーションを作成しています。私は 3 つの pthread を持っています - そのうちの 1 つは「スケジューラー」と呼ばれ、他の 2 つは「ワーカー」と呼ばれ、メインスレッドです。メイン スレッドはイベントをリッスンし、それらをキューに入れます。次に、スケジューラ スレッドがそれらをワーカー キューにディスパッチします。ワーカー スレッドは、ワーカー キューからイベントを取得して実行します。問題は、主要なデータ競合を防ぐために、メインスレッド自体でイベントを実行する必要がある場合があります。したがって、特別なイベントが受信されたときにメイン スレッドを一時停止し、すべてのワーカーがジョブを終了するまで待機してから、このイベントを実行するメカニズムが必要です。

これを行うために、ミューテックスによって保護された整数を使用します。ミューテックスのビットは、ワーカー スレッドによって設定およびリセットされます。キューにジョブが見つからない場合、ワーカーはビットを 0 に設定します。ジョブがある場合は、ビットを 1 としてマークします。ワーカーの 1 つが実行されている場合、整数は != になります。 0. メイン スレッドは、ワーカーが終了するまで一時停止する必要がある場合、整数が 0 になるまで条件付き待機を行います。ワーカー スレッドは、ビットをリセットするときに、整数が 0 になるかどうかをチェックします。true の場合、メインスレッドに通知します。この時点で、すべてのワーカーのキューにジョブがなく、メイン スレッドが特別なイベントを実行できることを期待しています。メイン スレッドがイベントを最初のキューにキューイングする役割を担っているため、ワーカーにイベントが忍び込むことはありません。

擬似コードは次のとおりです。

int pause_threads() => the one called from main thread.  
{  
  pthread_mutex_lock(pause_thread_lock));  

  while (pthread_states != 0) {  
  pthread_cond_wait(pause_mthread_cond), pause_thread_lock));  
  }  

}  

int thread_resume()  => called after the special event is executed by main thread.  
{  
  pthread_mutex_unlock(pause_thread_lock));  
}  

int thread_set_state_wait(index) => index is id 0,1 for each worker  
{  
 pthread_mutex_lock(pause_thread_lock));  
 (thread_states) &= (~(MTHREAD_THR_STATE_RUNNING << index));  
  if (pthread_states == 0)  
     pthread_cond_signal(pause_thread_cond));  
  pthread_mutex_unlock(&(pause_thread_lock));  
}  

 int thread_set_state_running(index)  
{  
   pthread_mutex_lock(pause_thread_lock));  
  (pthread_states) |= (MTHREAD_THR_STATE_RUNNING << index);  
   pthread_mutex_unlock(pause_thread_lock));  

}   

私が直面している問題は、このコードが常に機能していないことです。メイン スレッドが特別なイベントを実行している間に、ワーカー スレッドがまだアクティブでジョブを実行していることが時々あります。ロジックに何か問題がありますか?これを達成する他の方法はありますか?私は解決策を探すために最善を尽くしました。助けてください。

4

1 に答える 1

0

これはトリッキーです。メイン ルーチンがクリティカル セクションに入るときは、次のことを確認する必要があります。

  1. スケジューラはこれ以上作業をスケジュールしません
  2. 労働者は仕事を終えた

これらは両方とも、他のスレッドからの確認が必要です。なんらかのメッセージ パッシング メカニズムを作成するか、既存のものを使用する場合は、代わりに通信の問題として書き出す方が簡単かもしれません。ただし、mutex と condvar の標準セットを使用すると、おそらく次のように構成することになります。

  • スケジューラー
    1. 作業のスケジューリング時に、処理中のジョブをインクリメントします (ミューテックスによってロックされます)。
  • 労働者
    1. 作業とブロードキャストが終了したら、進行中のジョブ (ミューテックスによってロック) を減らします
  • 主要
    1. クリティカル セクションが必要な場合、クリティカル セクションが進行中であることを示すフラグ (mutex によってロックされる) を設定し、この状態が変化したことを condvar でブロードキャストします。
    2. エントリが進行中であることを示すフラグ (これもロックされています) を設定し、状態の変化をブロードキャストします
    3. スケジューラーがフラグをゼロに設定することによって応答するのを進行中の condvar で待機します。
    4. ジョブ インフライト condvar でワーカーが終了するのを待ちます。
    5. 進行中およびブロードキャストの設定を解除して、スケジューラのブロックを解除します
  • スケジューラー
    1. 作業を開始する前または condvar でチェックして、メインが入りたいかどうかを確認します
    2. 進行中のエントリ フラグを設定解除し、確認のためにブロードキャストします。
    3. main が終了するまでクリティカル進行中の condvar を待機します

これらすべてが整ったら、main はこれ以上作業がスケジュールされず、進行中のすべての作業が完了したことを確認できます。それはそのことを行うことができ、スケジューラのブロックを解除します。

于 2013-09-02T07:37:29.387 に答える