0

私のプログラムは、行のフィールドの 1 つに応じて異なるスレッドでデータベースの行を処理します。メイン スレッドは「ワーカー」から生成され、クエリを実行します。次に、行ごとに、いずれかのワーカーが行を消費するためにすべてのワーカーを起動する必要があります。

現在、 pthread_cond_broadcast() を使用するのが最も論理的な選択のようです。ただし、この場合のワーカーはすべて、同じミューテックスを使用してpthread_cond_wait() 内で待機する必要があります。

私の場合、これは最適ではありません。これは、ワーカーが一度に 1 つずつ起動されるのではなく (これは必要ありません) 、一度に起動されることを意味するためです。はい、私はそれらすべてをウェイクアップさせたいと思っています-それらはすべて新しいDB行から1つのフィールドを読み取り、その後、1つを除いてすべてが次の行を待つために戻ります。それらを同期する必要はありません。

各スレッドでダミーのスレッド固有のミューテックスを pthread_cond_wait() で使用すると思いましたが、それは機能しません (1 つのスレッドのみが起動されます)。標準では、異なるミューテックスを使用して同じ条件変数を待機すること (私が行っているように) は定義されていません。

それで、一度にすべてのスレッドに通知する方法はありますか? ありがとう!

4

2 に答える 2

2

この問題について、またなぜこのようにしようとしているのかを説明する必要があると思います。最善の方法が、ミューテックスなしですべてのスレッドを一度に起動することを含まない、まったく異なることをすることであるとしても、私は驚かないでしょう。

私には、あなたの説明は次のように聞こえます。

  • メイン スレッドが複数のスレッドを生成します (スレッドの生成には比較的コストがかかります)。
  • メインスレッドはクエリを実行しますが、生成されたスレッドは開始され、ほとんど実行されず、ブロックされます (開始/再起動とブロックは比較的高価です)。
  • 行ごとに、メイン スレッドがすべてのスレッドを起動し (比較的高価な再起動とブロック)、そのうちの 1 つを除くすべてのスレッドが待機状態に戻ります (非常に無駄です)。

なぜこれを行っているのかわからなくても、スレッドをまったく使用しない方が高速になると思います(たとえば、メインスレッドが行を調べて通知するよりも、メインスレッドが行を高速に処理できるなど)生成されたスレッドを処理して、理由もなく他のスレッドに迷惑をかけます)。

行の処理に時間がかかる場合は、ワーカー スレッドを FIFO キューで待機させることを検討します。これにより、メイン スレッドが「この行を処理する」コマンドをキューにプッシュし、キューからそれを取得する最初のスレッドが処理されます。その行。

もちろん、あなたがやりたいことをやりたい理由はわかりません。したがって、提案は推測にすぎません。

TL;DR: あなたの質問は、体重を減らしたい人が「自分の足を切り落とす最善の方法は何か」と尋ねるようなものだと思います (最も実用的な答えは、実際に尋ねられた質問とは何の関係もありません)。

于 2012-12-30T07:25:25.783 に答える
0

条件変数では、排他的にチェックして更新する必要がある関連する「条件」(この場合はデータ行) があると想定されます (したがってミューテックス)。他のどのメカニズムを選択する場合でも、「作業キュー」への排他的アクセスを確保する方法を理解する必要があります (それが単一のスロットであるか実際のキューであるかに関係なく)。

共有キューを使用すると、データ構造に対して常に 2 つのライター (メイン スレッド + 目的のワーカー) と N-1 のリーダーが存在します。整合性を確保するために、読み書きロック (rwlock) を使用できます。

または、N 個の個別のキュー (ワーカーごとに 1 つ) を持つこともできます。データ行のコピーを各ワーカーにプッシュします。

一度に複数のスレッドを起動する限り、ワーカーを「スリープ」させ (たとえば、select() を使用)、pthread_signal() を使用して (ループで) 起動させることができます。

pthread_barrier_wait()を使用することもできます。

pthread_barrier_wait() 関数は、バリアによって参照されるバリアで参加スレッドを同期します。呼び出しスレッドは、必要な数のスレッドがバリアを指定して pthread_barrier_wait() を呼び出すまでブロックします。

必要な数のスレッドがバリアを指定して pthread_barrier_wait() を呼び出した場合、定数 PTHREAD_BARRIER_SERIAL_THREAD が 1 つの未指定のスレッドに返され、残りの各スレッドにゼロが返されます。この時点で、バリアは、それを参照した最新の pthread_barrier_init() 関数の結果としての状態にリセットされます。

  1. pthread_barrier_init()でバリアを初期化します(カウント = 1 + ワーカー数)
  2. 各ワーカーで、ループ内で pthread_barrier_wait() を呼び出します。それが戻ると、新しいデータの準備ができています
  3. メインスレッドで、 pthread_barrier_wait() を呼び出してワーカーに通知します

残念ながら (OP に記載されているように)、次の反復では、以前にアクティブ化されたワーカーがジョブを完了するまで、ワーカーは起動されません。

より単純なアーキテクチャでは、メイン スレッドがイベントを適切なワーカーにディスパッチします (すべてのワーカーを起動して、どのワーカーが意図した受信者であるかを判断させるのではなく)。ワーカーと同じ数のコアがない限り、テストは実際には並行して行われません。また、ワーカーを並行して実行するのに十分なコアがある場合でも、そのうちの N-1 は、テストが完了する前に「勝者」がジョブを引き受けたことを学習しないため、すべてのコアの合計作業量は高くなります。 .

于 2012-12-30T06:23:44.297 に答える