0

次のコードは単純なスレッドゲームで、スレッドを切り替えてタイマーを減らします。

3つのスレッドでは正常に動作し、4つのスレッドではAbort(コアダンプ)が発生し、5つ以上のスレッドではセグメンテーション違反が発生します。

なぜこれが起こっているのか誰かが知っていますか?

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <assert.h>

int volatile num_of_threads;
int volatile time_per_round;
int volatile time_left;
int volatile turn_id;
int volatile thread_running;
int volatile can_check;
void *  player (void * id_in){
 int id= (int)id_in;
 while(1){
  if(can_check){
   if (time_left<=0){
    break;
   }
   can_check=0;
   if(thread_running){
    if(turn_id==id-1){
     turn_id=random()%num_of_threads;
     time_left--;
    }
   }
   can_check=1;
  }
 }
 pthread_exit(NULL);
}
int main(int argc, char *args[]){
 int i;
 int buffer;
 pthread_t * threads =(pthread_t *)malloc(num_of_threads*sizeof(pthread_t));
 thread_running=0;
 num_of_threads=atoi(args[1]);
 can_check=0;
 time_per_round = atoi(args[2]);
 time_left=time_per_round;
 srandom(time(NULL));
 //Create Threads
 for (i=0;i<num_of_threads;i++){
  do{
  buffer=pthread_create(&threads[i],NULL,player,(void *)(i+1));
  }while(buffer == EAGAIN);
 }
 can_check=1;

 time_left=time_per_round;
 turn_id=random()%num_of_threads;
 thread_running=1;

 for (i=0;i<num_of_threads;i++){
  assert(!pthread_join(threads[i], NULL));
 }
 return 0;
}
4

1 に答える 1

2

volatilepthreadに依存すべきでない理由については、以下を参照してください。ただし、特定の問題は、実際に設定するnum_of_threadsの変数に基づいて、pthread配列をmallocすることが原因である可能性があります。num_of_threadargv[]

pthread_t *threads = (pthread_t *)malloc (num_of_threads * sizeof (pthread_t));
thread_running = 0;
num_of_threads = atoi (args[1]);

したがって、配列の終わりを超えて書いている可能性は非常に高いです。起動時に変数はおそらくゼロになります。これは、自分が思っているものを割り当てていないことを意味しますthreads引数の抽出後num_of_threadsに割り当てを移動すると、修正されるはずです。


そして今、あなたの閲覧の喜びのために:-)、私volatileがまだ待機している、の安全でない使用についての私の最初の怒り。

共有変数の保護に依存しないでください。volatileこれを行う正しい方法は、pthread_mutex_blab_blah_blah呼び出しを使用することです。

特に注目すべきは、次のコードセグメントを調べてください。

if (can_check) {
   if (time_left <= 0) {
    break;
   }
   // URK!!
   can_check=0;

URK!!これは、現在のスレッドが切り替えられて別のスレッドが実行される可能性があるポイントであり、2つのスレッドがコードのクリティカルセクションを実行している可能性があります。

私のアドバイスは、can_check完全に忘れて、(メモリから)次のようなミューテックスですべての共有変数を保護することです。

void *player (void * id_in) {
    int id = (int)id_in;
    while (1) {
        pthread_mutex_lock (&mutex);
        if (time_left <= 0) {
            pthread_mutex_unlock (&mutex);
            break;
        }
        if (thread_running) {
            if (turn_id == id-1) {
                turn_id = random() % num_of_threads;
                time_left--;
            }
        }
        pthread_mutex_unlock (&mutex);
    }
    pthread_exit(NULL);
}

次に、ファイルレベルで配置します。

pthread_mutexattr_t mutexattr;  // prob. not needed at file level.
pthread_mutex_t mutex;

そして、主に、他のスレッドを開始する前に:

pthread_mutexattr_init (&mutexattr);
// Change attributes if needed.
pthread_mutex_init (&mutex, &mutex_attr);

// Then run all you other stuff here, make sure you've joined with all threads.

pthread_mutex_destroy (&mutex);

そうそう、私はそれをしていませんが、それらすべてのミューテックス呼び出しのリターンコードもチェックする必要があります。不必要な詳細で答えを詰まらせるので、それを追加するつもりはありませんが、それは良い習慣です。

于 2010-03-12T03:49:04.520 に答える