2011-07-28 9 views
0

私はlinuxの下でC++で動作するmpi(openmpi 1.4.3)とpthreadsを使用するプログラムに取り組んでいます。posixスレッドとO3の最適化

mpiノードの中には、pthreadsで実装されたキューシステムがあります。 アイデアは、要素をキューに追加する単純な1つのスレッド、およびオブジェクトをピックアップしてそれらのジョブを実行する他の「動作中の」スレッドはほとんどありません(ロケット科学ではありません)。

要素を取り上げている私の作業スレッドの2つの例を考えてください。 -O3最適化が指定されていない限り、最初の例は正常に動作します。その場合、何も拾わずに無限にループし始めます。

while (true){ 
     if (t_exitSignal[tID]){ 
      dorun = false; 
      break; 
     } 

     //cout<<"w8\n"; 

     //check if queue has some work for us 
     if (!frame_queue->empty()){ 

      //try to get lock and recheck that queue no empty 
      pthread_mutex_lock(&mutex_frame_queue); 

      if (!frame_queue->empty()){ 
       cout<<"Pickup "<<tID<<endl; 
       con = frame_queue->front(); 
       frame_queue->pop(); 
       t_idling[tID] = false; 
       pthread_mutex_unlock(&mutex_frame_queue); 
       break; 
      } 

      pthread_mutex_unlock(&mutex_frame_queue); 
     } 

    } 

は今、私はqueue-> empthyをチェックする前にロックされたミューテックスgettimg除いて、この1、まったく同じコードを考えてみましょう。この作業は、すべてのレベルの最適化に適しています。

while (true){ 
     if (t_exitSignal[tID]){ 
      dorun = false; 
      break; 
     } 
     //cout<<"w8\n"; 

     //try to get lock and recheck that queue no empty 
     pthread_mutex_lock(&mutex_frame_queue); 

     //check if queue has some work for us 
     if (!frame_queue->empty()){ 

       cout<<"Pickup "<<tID<<endl; 
       con = frame_queue->front(); 
       frame_queue->pop(); 
       t_idling[tID] = false; 
       pthread_mutex_unlock(&mutex_frame_queue); 
       break; 

     } 
     pthread_mutex_unlock(&mutex_frame_queue); 

    } 

は、念のために、これは私が他のスレッドから

    pthread_mutex_lock(&mutex_frame_queue); 
      //adding the same contianer into queue to make it available for threads 
      frame_queue->push(*cursor); 
      pthread_mutex_unlock(&mutex_frame_queue); 

をキューに移入する方法で違いを作る私の質問は:私は-O3オプションを指定してコンパイルし、なぜ、なぜ、コードストップの最初の例では、作業しますか? キューイングシステムに関する他の提案はありますか?

ありがとうございます!

解決策:これは私が最後に思いつくものです。上記のいずれの方法よりもはるかにうまくいくと思われます。 (念の誰かに興味を持って;)

while (true){ 

     if (t_exitSignal[tID]){ 

      dorun = false; 
      break; 
     } 
     //try to get lock and check that queue no empty 
     pthread_mutex_lock(&mutex_frame_queue); 

     if (!frame_queue->empty()){ 

      con = frame_queue->front(); 
      frame_queue->pop(); 
      t_idling[tID] = false; 
      pthread_mutex_unlock(&mutex_frame_queue); 
      break; 
     }else{ 

      pthread_cond_wait(&conf_frame_queue, &mutex_frame_queue); 
      pthread_mutex_unlock(&mutex_frame_queue); 
     } 




    } 

は、私は、キューが空であるかどうかをチェックするときに、命令の順序についての仮定に基づいてバグを見ている推測している

 pthread_mutex_lock(&mutex_frame_queue); 

     //adding the same contianer into queue to make it available for threads 
     frame_queue->push(*cursor); 
     //wake up any waiting threads 
     pthread_cond_signal(&conf_frame_queue); 
     pthread_mutex_unlock(&mutex_frame_queue) 

答えて

1

を追加する - あなたは電源を入れたときあなたが持っているミューテックスがこれを防ぐためのメモリバリヤーを設けていないので、順序が変わると最適化が上がります。

2

最初に空のチェックを行う前に__sync_synchronize()を提示することをお勧めしますが、安全でない可能性があります。empty()を呼び出すと、別のスレッドがコンテナに追加中でもコンテナが不整合な状態になることがあります。コンテナによっては、間違った答えを取り戻してクラッシュするまで何かが起こる可能性があります。

Joshもそうでしょう。ミューテックスをロックすると、メモリの壁が提供されます。これは、コンテナが毎回空であるかどうかを判断するために使用するメモリをコードが再読み込みすることを意味します。何らかのメモリー障壁がなければ、それは実際に起こることは決してありません。そのため、最適化レベルが高くなると、コードに変更が反映されないことがあります。

さらに、pthreadのcondition variablesについて調べましたか?彼らはあなたのコンテナがもう空にならなくなるまで、ループでポーリングを避けることができます。