2

条件変数を使用して2つのスレッド間の同期を作成する単純なプログラムを作成しました。解決策が見つからないような奇妙な出力が表示されます。

プログラムが行うことは、ジェネレータスレッドで、1000個のランダムな整数を生成し、それらが完全な平方であるかどうかを確認することです。数値が完全な平方である場合、数値の平方根を出力するモニタースレッドに信号を送ります。

私が抱えている問題は、ジェネレーターが信号を送ったときにモニターが平方根を出力しないため、ある種の競合状態である可能性があります。

奇妙な部分は、変数が変更されるたびにステップスルーするgdb bでデバッグis_squareすると、問題が存在しないことです。

任意の洞察をいただければ幸いです。私はそれが私のミューテックスまたは条件の配置に関係していると感じています。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
#include <time.h>

int square_root;
int is_square = 0;
int done = 0;
int count = 0; //used to count how many perfect squares generator_func finds
int count1 = 0; //used to compare how many responses monitor makes to signal
pthread_mutex_t mutex;
pthread_cond_t mon;


void* generator_func(void* args){
  srand(time(NULL)); 
  int i, temp, sq;
  for(i = 0; i<1000; i++){
    temp = rand() % 10000;
    sq = sqrt((double)temp);
    if((pow(sq,2)) == temp){
      pthread_mutex_lock(&mutex);
      count++;
      square_root = sq;
      is_square = 1;
      fprintf(stderr, "Square root of %d is", temp);
      pthread_cond_signal(&mon);
      pthread_mutex_unlock(&mutex);
    } 
  }
  pthread_mutex_lock(&mutex);
  done = 1;
  is_square = -1;
  pthread_cond_signal(&mon);
  pthread_mutex_unlock(&mutex);
}


main(){
  pthread_t generator; //declare thread

  pthread_mutex_init(&mutex, NULL); //initialize mutex
  pthread_cond_init(&mon, NULL); //initialize condition variable


  pthread_create(&generator, NULL, generator_func, NULL); //create thread

  //monitor
  while(done != 1){
    pthread_mutex_lock(&mutex);
    while(is_square == 0){
      pthread_cond_wait(&mon, &mutex);
    }
    if(is_square == 1 && done != 1){
      count1++;
      fprintf(stderr, " %d\n", square_root);
      is_square = 0;
    }
    pthread_mutex_unlock(&mutex);
  }

  pthread_join(generator, NULL);

  printf("%d %d\n", count, count1); //shows inconsistency between generator and monitor
  pthread_mutex_destroy(&mutex);
  pthread_cond_destroy(&mon);
} 
4

4 に答える 4

2

条件変数に注意してください。ここに1つの大きな落とし穴があり、それはおそらくあなたに起こっています。条件変数でシグナルを呼び出したが、それを待機しているスレッドがない場合、シグナルは失われます。

私の推測では、ジェネレータースレッドがシグナルを呼び出すまでにメインスレッドが待機の呼び出しに到達することはできません(メインスレッドが待機に達するまでに数回呼び出す可能性があります)。そのため、いくつかの値が失われています。

デバッガーは、これらの微妙なタイミングのバグをなくす傾向があるため、これを調べるのに適した方法ではありません。

その他の問題:

  1. メインスレッドがしばらく到達する前にジェネレータが終了する場合があります。
  2. クロススレッドで変更されているため、doneは揮発性である必要があります。
于 2011-11-23T16:48:14.700 に答える
1

すべての共有(グローバル)変数をミューテックスで保護する必要があります。まず、これはミューテックス呼び出しを次の場所に移動することを意味しますmain

pthread_mutex_lock(&mutex);
while(done != 1){
   while(is_square == 0){
...
}
pthread_mutex_unlock(&mutex);

次に、ジェネレータが検出したすべての平方根ではなく、ほんの一握りの平方根しか表示されないことに注意する必要があります。mainジェネレーターが十分に高速である場合、サブスレッドはループを確認する前に実行を終了できるため、平方根も表示されませんwhile (done != 1)

見つかった平方根を格納するためにバッファを使用することを検討してください。

于 2011-11-23T16:50:43.487 に答える
0

このコードはトリックを行う必要があります:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>

int square_root;
int is_square = 0;
int done = 0;
int count = 0; //used to count how many perfect squares generator_func finds
int count1 = 0; //used to compare how many responses monitor makes to signal
pthread_mutex_t mutex;
pthread_cond_t mon;


void* generator_func(void* args){

    //sleep(1);
    for(int j=0; j<1000; j++);  // Some delay to hit a time-slice

  srand(time(NULL)); 
  int i, temp, sq;
  for(i = 0; i<1000; i++){
    temp = rand() % 10000;
    sq = sqrt((double)temp);
    if((pow(sq,2)) == temp){
      pthread_mutex_lock(&mutex);
      count++;
      square_root = sq;
      is_square = 1;
      fprintf(stderr, "Square root of %d is", temp);
      pthread_cond_signal(&mon);
      pthread_mutex_unlock(&mutex);
    } 
  }
  pthread_mutex_lock(&mutex);
  done = 1;
  is_square = -1;
  pthread_cond_signal(&mon);
  pthread_mutex_unlock(&mutex);
}


int main(){
  pthread_t generator; //declare thread

  pthread_mutex_init(&mutex, NULL); //initialize mutex
  pthread_cond_init(&mon, NULL); //initialize condition variable


  pthread_create(&generator, NULL, generator_func, NULL); //create thread

  //monitor
    pthread_mutex_lock(&mutex);  // Protect your variables here
  while(done != 1){
    while(is_square == 0){
      pthread_cond_wait(&mon, &mutex);
    }
    if(is_square == 1 && done != 1){
      count1++;
      fprintf(stderr, " %d\n", square_root);
      is_square = 0;
    }
  }
    pthread_mutex_unlock(&mutex);

  pthread_join(generator, NULL);

  printf("%d %d\n", count, count1); //shows inconsistency between generator and monitor
  pthread_mutex_destroy(&mutex);
  pthread_cond_destroy(&mon);

return 0;
}

メインがcond_signal()を待つために急ぐことができるように、前にタイムスライスをヒットするのに十分な長さの遅延ループを作成できます。別の方法として、generator_func()スレッドがメインスレッドからのシグナルを待機できるようにする別のメカニズムを用意することです。

繰り返しになりますが、ライブラリでサポートされている場合に使用できるsleep()機能があります。

お役に立てば幸いです。

乾杯、ヴァーン

于 2011-11-23T17:20:09.210 に答える
0

すべて、私はこの問題を非常に簡単に解決しました。これを早くキャッ​​チできなかったのは恥ずかしいですが、しばらくの間このコードから休憩しました。解決策はとても簡単です。必要なのは、モニターが終了するまでジェネレーターが待機する追加の条件変数だけでした。これがコードです。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
#include <time.h>

int square_root;
volatile int is_square = 0;
int done = 0;
int count = 0; //used to count how many perfect squares generator_func finds
int count1 = 0; //used to compare how many responses monitor makes to signal
pthread_mutex_t mutex;
pthread_cond_t mon, gen;


void* generator_func(void* args){
  srand(time(NULL)); 
  int i, temp, sq;
  for(i = 0; i<1000; i++){
    temp = rand() % 10000;
    sq = sqrt((double)temp);
    if((pow(sq,2)) == temp){
      pthread_mutex_lock(&mutex);
      count++;
      square_root = sq;
      is_square = 1;
      fprintf(stderr, "Square root of %d is", temp);
      pthread_cond_signal(&mon); //signal monitor
      pthread_cond_wait(&gen, &mutex); //wait for monitor to finish *Solution*
      pthread_mutex_unlock(&mutex);
    } 
  }
  pthread_mutex_lock(&mutex);
  done = 1;
  is_square = -1;
  pthread_cond_signal(&mon);
  pthread_mutex_unlock(&mutex);
}


main(){
  pthread_t generator; //declare thread

  pthread_mutex_init(&mutex, NULL); //initialize mutex
  pthread_cond_init(&mon, NULL); //initialize condition var for monitor
  pthread_cond_init(&gen, NULL); //initialize condition var for generator

  pthread_create(&generator, NULL, generator_func, NULL); //create thread

  //monitor
  pthread_mutex_lock(&mutex);
  while(done != 1 || is_square == 1){
    while(is_square == 0){
      pthread_cond_wait(&mon, &mutex);
    }
    if(is_square == 1 && done != 1){
      count1++;
      fprintf(stderr, " %d\n", square_root);
      is_square = 0;
    }
    pthread_cond_signal(&gen); //start generator back up *Solution*
  }
  pthread_mutex_unlock(&mutex);


  pthread_join(generator, NULL);

  printf("%d %d\n", count, count1); //shows inconsistency between generator and monitor
  pthread_mutex_destroy(&mutex);
  pthread_cond_destroy(&mon);
}
于 2011-11-28T19:41:39.200 に答える