0

この種のキューを素朴な方法で実装するのはなぜ間違っているのだろうかと思います。

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>


void *print_message_function( void *ptr );

void *reader( void *ptr );
void *writer( void *ptr );



int queue[500000];


int main(int argc, char **argv) 
{
   pthread_t thread1, thread2;

   char *message1 = "Thread 1";
   char *message2 = "Thread 2";
   int  iret1, iret2; 


   iret1 = pthread_create( &thread1, NULL, writer, (void*) message1);
   iret2 = pthread_create( &thread2, NULL, reader, (void*) message2);

   usleep(2000);

   void pthread_exit(void *iret1 );
   void pthread_exit(void *iret2 );

   exit(0);

}



void *writer( void *ptr )
{
  // make local copy of queue head
  register int *pos = queue; 

  //   struct thread_param *tp = arg;
  int counter = 0;

  while(1)
  {
    //Write to head of queue
    *pos = 5;

    pos++;

    print_message_function(  ptr);
  }
}


void *reader( void *ptr )
{
  int counter = 0;

  // make local copy of queue head
  register int *pos = queue; 

  while(1)
  {

    // Read from tail of queue - loop when nothing
    if ( *pos == 5 ) 
    { 
      print_message_function( ptr ); 
      pos++; 
    }
  }
}



void *print_message_function( void *ptr )
{
      char *message;
      message = (char *) ptr;
      printf("%s \n", message);
}

キューをキャッシュアラインするつもりです。

キューヘッドのコピーが開始時に作成され、リーダーとライターが1つしかないため、メモリの並べ替えが問題になるとは思いません。

これが必要な理由は、ミューテックスロックやCAS操作よりも高速である必要があるためです。

4

2 に答える 2

2

POSIXスレッドでは、ミューテックスやロックなどを使用する場合にのみ、スレッド間のデータコヒーレンスがあります。コヒーレンスには、コンパイラとの明確に定義されたインターフェイスがありません。(そしてvolatile間違いなくそうではありません)そのようにしないでください。最適化された変数の更新(ここでvolatile役立つ可能性があります)または部分的な読み取りまたは書き込みとして、すべてのことが起こる可能性があります。

C11、新しいC標準には、データコヒーレンスモデル、スレッド作成関数、およびアトミック操作を含むスレッドモデルがあります。これを完全に実装するコンパイラはないようですが、POSIXスレッドの上にあるgccまたはclangは、必要な機能を実装します。これを試して将来を保証したい場合は、P99がこれらのプラットフォーム用のラッパーを実装して、新しいC11インターフェイスを使用できるようにします。

C11の_Atomicタイプと操作は、スレッド間で動作するロックフリーキューを実装するための正しいツールになります。

于 2012-07-07T18:48:44.603 に答える
1

Cでは、volatileキーワードには、変数が複数のスレッドで同時にアクセスされる場合に適用される定義済みのセマンティクスがありません(pthreadは何も追加しません)。したがって、安全かどうかを知る唯一の方法volatileは、特定のプラットフォームとコンパイラでの影響を調べ、それらの特定のハードウェアプラットフォームで問題が発生する可能性のあるすべての方法を見つけ出し、それらを除外することです。

選択肢があれば、これを行うのは本当に悪い考えです。ポータブルコードははるかに信頼性が高い傾向があります。2つの大きな問題は次のとおりです。

  1. 新しいプラットフォームが出てきます。また、新しいCPU、コンパイラ、またはライブラリがリリースされると、壊れやすいコードが破損する可能性があります。

  2. 何を扱っているのかよくわからないため、これがうまくいかない可能性があるすべての方法を考えるのは非常に困難です。ミューテックス、不可分操作などは、複数のスレッドに対して正確に定義されたセマンティクスを持っているため、プラットフォーム、コンパイラ、ハードウェアを問わず、どのような保証があるかを正確に把握できます。

ちなみにあなたのリーダーコードはひどいです。たとえば、ハイパースレッディングCPUでは、そのようにしっかりと回転すると、他の仮想コアが不足します。さらに悪いことに、他の物理コアを枯渇させて、FSB速度で回転してしまう可能性があります。そして、スピンループを終了すると(時間のパフォーマンスが最も重要です)、基本的に予期しない分岐を強制します!(正確な効果はCPUの詳細によって異なります。これは、この種のコードを使用することが悪いもう1つの理由です。少なくともrep nopが必要です。)

于 2012-07-07T18:11:00.530 に答える