2016-12-24 12 views
1

私は可能な限りライターよりも優先順位が高くなるように、一般的なリソースを共有する "リーダー"と "ライター"スレッドを作成する基本的なプログラムを作成しようとしています。私はmutex構造体を使ってこのリソースを保護していますが、コードの動作は私が期待したものではありません。私は問題を1行のコードにトレースしましたが、なぜ動作しないのか分かりません。 「バグ」は必ずしも発生するわけではありませんが、これはスレッドでは期待されますが、発生したときに私はそれについて適切な説明を見つけることができません!ここ は私のプログラムは次のとおりです。予期せぬpthread出力

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <unistd.h> 

#define N 3 //Number of readers. 
#define M 3 //Number of writers. 
#define X 2 //Number of times a reader reads. 
#define Y 2 //Number of times a writer writes. 

pthread_mutex_t res_mutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t res_cond_read = PTHREAD_COND_INITIALIZER; 
pthread_cond_t res_cond_write = PTHREAD_COND_INITIALIZER; 
int resource = 0, state = 0 /*1 = writing, 0 = waiting, abs(<0) = #readers*/, reader_queue_length = 0; 

void *reader_job (void* parg); 
void *writer_job (void* parg); 

int main() 
{  
    srandom((unsigned int)time(NULL)); 

    pthread_t readers[N]; 
    pthread_t writers[M]; 
    int valueR[N], valueW[M]; 

    //printf ("NOTICE: Reader queue lengths excluding current thread.\n"); 
    for (int i=0; i<N; i++) {  
     valueR[i] = i; 
    } 

    for (int i=0; i<M; i++) {  
     valueW[i] = i; 
    } 
    for (int i=0; i<N; i++) {  
     pthread_create (&readers[i], NULL, reader_job, &valueR[i]);      
    } 

    for (int i=0; i<M; i++) { 
     pthread_create (&writers[i], NULL, writer_job, &valueW[i]); 
    } 

    for (int i=0; i<N; i++) { 
     pthread_join (readers[i], NULL);   
    } 

    for (int i=0; i<M; i++){ 
     pthread_join (writers[i], NULL); 
    } 
    return 0; 
} 

void *reader_job (void* parg) { 
    int *temp = (int*) parg; 
    int value = *temp; 
    int local_read_num = 0; 
    printf (">>> Creating reader: %d\n", value); 
    while (local_read_num < X) { 
     usleep(1000 * (random() % (N+M)));    
     reader_queue_length++; //When this line is here, wrong. 
     printf ("INFO::About to access entry mutex for reader with ID: %2d, with queue length %2d.\n", 
      value, reader_queue_length); 
     pthread_mutex_lock(&res_mutex); 
      //reader_queue_length++; //When it is here, right. 
      if (reader_queue_length == 0) printf ("\nERROR::Before entry mutex!\n\n");   
      while (state != 0) 
       pthread_cond_wait (&res_cond_read, &res_mutex); 
      state--; 
      if (reader_queue_length == 0) printf ("\nERROR::During entry mutex!\n\n"); 
      reader_queue_length--; 
      printf ("INFO::About to exit entry mutex for reader with ID: %2d, with queue length %2d.\n", 
       value, reader_queue_length); 
     pthread_mutex_unlock (&res_mutex); 

     printf ("[READER (ID: %2d):] Readers in queue: %2d, read: %2d\n", value, reader_queue_length, resource); 

     pthread_mutex_lock (&res_mutex); 
      state++; 
      pthread_cond_signal (&res_cond_read); 
      if (reader_queue_length == 0) pthread_cond_signal (&res_cond_write);       
     pthread_mutex_unlock (&res_mutex); 


     local_read_num++; 
    } 
    printf ("!!! Destroying reader: %d\n", value); 
    pthread_exit (NULL); 
} 

void *writer_job (void* parg) { 
    int *temp = (int*) parg; 
    int value = *temp; 
    int local_write_num = 0; 
    printf (">>> Creating writer: %d\n", value); 
    while (local_write_num < Y) { 
     //usleep(1000 * (random() % (N+M))); 
     pthread_mutex_lock(&res_mutex); 
      while (state != 0 || reader_queue_length > 0) 
       pthread_cond_wait (&res_cond_write, &res_mutex);  
      state++; 
     pthread_mutex_unlock(&res_mutex); 

     resource = value*5+local_write_num; 
     printf ("[WRITER (ID: %2d):] Readers in queue: %2d, wrote: %2d\n", value, reader_queue_length, resource); 

     pthread_mutex_lock (&res_mutex); 
      state--; 
     pthread_mutex_unlock(&res_mutex); 

     pthread_cond_signal(&res_cond_read); 
     pthread_cond_signal(&res_cond_write); 
     local_write_num++; 
    } 
    printf ("!!! Destroying writer: %d\n", value); 
    pthread_exit (NULL); 
} 

ラインを見てみると(reader_jobに)reader_queue_length ++ ;,私はプログラムが動作しない理由のラインがミューテックスの外にあるときに得ることはありませんが、それがあるときに動作しません内部! 「バグ」は最後に(この特定の実行インスタンスでは、下を参照)、すべてのスレッドがすでに結合されているので、私の変数を変更する権限がないので、出力はさらに混乱します。

>>> Creating reader: 0 
>>> Creating reader: 1 
>>> Creating reader: 2 
>>> Creating writer: 0 
INFO::About to access entry mutex for reader with ID: 1, with queue length 1. 
INFO::About to exit entry mutex for reader with ID: 1, with queue length 0. 
[READER (ID: 1):] Readers in queue: 0, read: 0 
>>> Creating writer: 2 
>>> Creating writer: 1 
[WRITER (ID: 0):] Readers in queue: 0, wrote: 0 
[WRITER (ID: 0):] Readers in queue: 0, wrote: 1 
!!! Destroying writer: 0 
[WRITER (ID: 1):] Readers in queue: 0, wrote: 5 
[WRITER (ID: 1):] Readers in queue: 0, wrote: 6 
!!! Destroying writer: 1 
[WRITER (ID: 2):] Readers in queue: 0, wrote: 10 
[WRITER (ID: 2):] Readers in queue: 0, wrote: 11 
!!! Destroying writer: 2 
INFO::About to access entry mutex for reader with ID: 1, with queue length 1. 
INFO::About to exit entry mutex for reader with ID: 1, with queue length 0. 
[READER (ID: 1):] Readers in queue: 0, read: 11 
!!! Destroying reader: 1 
INFO::About to access entry mutex for reader with ID: 2, with queue length 1. 
INFO::About to exit entry mutex for reader with ID: 2, with queue length 0. 
[READER (ID: 2):] Readers in queue: 0, read: 11 
INFO::About to access entry mutex for reader with ID: 0, with queue length 1. 
INFO::About to exit entry mutex for reader with ID: 0, with queue length 0. 
[READER (ID: 0):] Readers in queue: 0, read: 11 
INFO::About to access entry mutex for reader with ID: 0, with queue length 1. 
INFO::About to exit entry mutex for reader with ID: 0, with queue length 0. 
[READER (ID: 0):] Readers in queue: 0, read: 11 
!!! Destroying reader: 0 
INFO::About to access entry mutex for reader with ID: 2, with queue length 1. 

ERROR::Before entry mutex! 


ERROR::During entry mutex! 

INFO::About to exit entry mutex for reader with ID: 2, with queue length -1. 
[READER (ID: 2):] Readers in queue: -1, read: 11 
!!! Destroying reader: 2 

どのようにリーダキューが負の長さになるのですか?内容を変更するために残されたスレッドはどれですか?彼らはすでに破壊されていましたが、少なくとも実行サイクル中のポイントを過ぎて、変数を混乱させる可能性がありました!

私はこれをgccコンパイラと-pthreadフラグを使ってUbuntu 16.04で実行しています。

ありがとうございました!

答えて

0

いいえ、私はこれが問題だと思っています:mutex外のキューの長さ変数を編集しようとすると、複数のスレッドが同じ変数に同時にアクセスしてデータ競合を起こすことがあります。

たとえば、変数の値がAで、アクセスしようとするコマンドが値をA + 1に編集しようとすると、変数にアクセスしようとしているスレッドがすべての場合、お互いが変数を編集してから更新された値を取得するのを適切に待つことなく、初期値Aを返します。だから、mutexに入る前に、それらはすべて値A + 1で終わってしまい、それは "バグ"を引き起こします。

ボトムライン:そのコマンドは、ミューテックスの内側にある必要があります!

関連する問題