条件変数を用いた有限バッファ問題のプログラムにおける間違いの解説

このQ&Aのポイント
  • 条件変数を用いた有限バッファ問題のプログラムには間違いがあります。
  • 問題の原因は、バッファへのデータの挿入と取り出しの条件が逆になっていることです。
  • また、生産者スレッドと消費者スレッドの終了条件が異なるために正しい結果が得られません。
回答を見る
  • ベストアンサー

条件変数を用いた有限バッファ問題を考えています。

皆さんこんにちは。 当方、プログラミングを勉強中の学生です。 条件変数を用いた有限バッファ問題を考えております。 以下に示すソースにおいて、関数produce()は1から1000までの整数を順に生成し、関数consume()はバッファから取り出した値の合計(1から1000までの和、500500となる)を求めるようプログラミングしているつもりなのですが、コンパイルして実行すると思ったような結果となりません。 どこが間違っているかご教授いただければ幸いです。 よろしくお願い致します。 以下、ソースとなります。 #include <stdio.h> #include <pthread.h> #define N 5 int buffer[N]; int inptr = 0, outptr = 0; int count = 0; int i = 0; int j = 0; int sum = 0; pthread_cond_t full = PTHREAD_COND_INITIALIZER; pthread_cond_t empty = PTHREAD_COND_INITIALIZER; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; int produce (void) { i += 1; return i; } void consume (int x) { j += 1; sum += x; } void *producer(void *arg) { int data; for (;;) { if (i >= 1000) break; data = produce(); pthread_mutex_lock(&lock); while (count > N) pthread_cond_wait(&full, &lock); count = count + 1; buffer[inptr] = data; inptr = (inptr + 1) % N; pthread_mutex_unlock(&lock); pthread_cond_signal(&empty); } } void *consumer(void *arg) { int data; for (;;) { if (j >= 1000) break; pthread_mutex_lock(&lock); while (count == 0) pthread_cond_wait(&empty, &lock); count = count - 1; data = buffer[outptr]; outptr = (outptr + 1) % N; pthread_mutex_unlock(&lock); pthread_cond_signal(&full); consume(data); } } int main() { pthread_t a, b; pthread_create(&a, NULL, producer, NULL); pthread_create(&b, NULL, consumer, NULL); pthread_join(a, NULL); pthread_join(b, NULL); printf("sum = %d\n", sum); return 0; }

質問者が選んだベストアンサー

  • ベストアンサー
  • ky072
  • ベストアンサー率60% (85/140)
回答No.1

producer() 内の条件ですが、 > while (count > N) pthread_cond_wait(&full, &lock); ここの「count > N」を「count >= N」とすれば 良いのではないでしょうか。 リングバッファのサイズは N = 5 ですから、 有効な buffer の添字は 0 .. 4 となります。 まだ consume されていない領域に データを書き込んでしまっているのではないかと思います。

nun00nun
質問者

お礼

分かりやすい説明感謝致します。 綺麗に解決しました! ご指摘ありがとうございましたm(_ _)m

関連するQ&A

  • pthread_cond_wait 取りこぼし?

    はじめまして。 pthreadのお勉強がてら、パイプライン処理を実装してみようととりあえず実証コードを書いてみましたが、うまく意図した動きをしてくれません。 やりたいことは、処理ステージが2つあって、メインからステージ1をキックし、ステージ1は自分の処理が終わったらステージ2をキックするといった動作です。(メイン、ステージ1、ステージ2を並列に動作させたい) 取りあえず連鎖的に動作するか試したいだけなので、ステージ間のデータの受け渡しとかは、後で考えるとします。 それで、以下のような単純なコードを書きました。 期待する結果は、最後に表示される数値が 10000, 10000, 10000 になることですが、実際は、10000, 4401, 4401 のようにステージ1,2が少なくなります。 一応、それなりに調べて条件変数のセオリーに従い書いたつもりなのですが、どうしてこうなるか、ご教授ください。 test.c (空白を全角にしてあります) ------ #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> pthread_mutex_t   mutex1,           mutex2; pthread_cond_t   cond1,           cond2; int         ready1,           ready2; int         end1,           end2; int         count1,           count2; void * stage1( void *arg ) {   pthread_mutex_lock( &mutex1 );   while( 1 ) {     /* wait for my signal & job */     while ( ready1 == 0 ) {       pthread_cond_wait( &cond1, &mutex1 );     }     if ( end1 == 1 ){  /* is shutdown thread */       break;     }     /* my job. */     count1++;     /* job clear */     ready1 = 0;     /* forward next stage */     pthread_mutex_lock( &mutex2 );     ready2 = 1;     pthread_cond_signal( &cond2 );     pthread_mutex_unlock( &mutex2 );   }   pthread_mutex_unlock( &mutex1 );   return NULL; } void * stage2( void *arg ) {   pthread_mutex_lock( &mutex2 );   while( 1 ) {     while ( ready2 == 0 ) {       pthread_cond_wait( &cond2, &mutex2 );     }     if ( end2 == 1 ){       break;     }     count2++;     ready2 = 0;   }   pthread_mutex_unlock( &mutex2 );   return NULL; } int main( ) {   int     i;   pthread_t  t1,         t2;   pthread_mutex_init( &mutex1, 0 );   pthread_cond_init ( &cond1, 0 );   ready1 = 0;   end1  = 0;   count1 = 0;   pthread_create( &t1, 0, stage1, NULL );   pthread_mutex_init( &mutex2, 0 );   pthread_cond_init ( &cond2, 0 );   ready2 = 0;   end2  = 0;   count2 = 0;   pthread_create( &t2, 0, stage2, NULL );   for ( i=0; i<10000; i++ ){     pthread_mutex_lock( &mutex1 );     ready1 = 1;     pthread_cond_signal( &cond1 );     pthread_mutex_unlock( &mutex1 );   }   pthread_mutex_lock( &mutex1 );   ready1 = 1;   end1  = 1;   pthread_cond_signal( &cond1 );   pthread_mutex_unlock( &mutex1 );   pthread_join(t1, 0 );   pthread_cond_destroy( &cond1 );   pthread_mutex_destroy( &mutex1 );   pthread_mutex_lock( &mutex2 );   ready2 = 1;   end2  = 1;   pthread_cond_signal( &cond2 );   pthread_mutex_unlock( &mutex2 );   pthread_join(t2, 0 );   pthread_cond_destroy( &cond2 );   pthread_mutex_destroy( &mutex2 );   printf("%d, %d, %d\n", i, count1, count2);   return 0; } ------ gcc -o test -lpthread test.c 以上

  • pthread_cond_wait での mutex

    以下の様なサンプルプログラム(一部省略)があります。 bossスレッドが1秒ごとにworkerスレッドを起こして、workerスレッドは処理後、再び眠ります。 worker () { while (...) { * pthread_mutex_lock(&g_lock); pthread_cond_wait(&g_signal, &g_lock); * pthread_mutex_unlock(&g_lock); : } } boss() { while (...) { wait( 1 ); * pthread_mutex_lock(&g_lock); pthread_cond_signal(&g_signal) * pthread_mutex_unlock(&g_lock); } } waitで待機し、signalで起こされるのはわかるのですが、 mutexでロックしている意味がわかりません。 mutexが不必要な処理の場合、*部分はいらないのでしょうか?

  • 生産者消費者問題

    #define N 16 char buffer[N]; int count = 0; int in = 0; int out = 0; void producer() { char c; do{ while (count == N); 文字cを生成する; count = count + 1; buffer[in] = c; in = (in +1)%N; }while(1); } void consumer() { char c; do{ while(count == 0); c = buffer [out]; out = (out + 1) % N; count = count - 1; 文字cを処理する; }while(1) } 以上のプログラムには同期をとるためのコードが抜けているため正しく動作しないのですが、具体的に「どういった動作」が起きてしまうのかを教えて頂きたいです。

  • pThreadのメインでなぜsleep?

    Windowsとlinux環境で、pthreadをもちいて、動作確認などをしています。 こちらのサンプルを下に、じっけんしていたのですが。 http://www.ibm.com/developerworks/jp/linux/library/l-posix3/ ここのメインのコードに, sleep(2) という表記があります。 なぜここでsleepをしなければいけないんでしょうか? 実際に、削除してみると、スレッドの作業が途中で終了してしまいました。 このやり方だと、作業時間がわかっている場合は、いいのですが、 もしどれぐらい処理にかかるかわからない場合、困ると思います。 どのようにすれば、sleepを使わずに作業が終わるのをまつことができるでしょうか? int main(void) { int x; wnode *mywork; initialize_structs(); /* CREATION */ if (create_threads()) { printf("Error starting threads... cleaning up.\n"); join_threads(); dabort(); } pthread_mutex_lock(&wq.control.mutex); for (x=0; x<16000; x++) { mywork=malloc(sizeof(wnode)); if (!mywork) { printf("ouch! can't malloc!\n"); break; } mywork->jobnum=x; queue_put(&wq.work,(node *) mywork); } pthread_mutex_unlock(&wq.control.mutex); pthread_cond_broadcast(&wq.control.cond); printf("sleeping...\n"); sleep(2); printf("deactivating work queue...\n"); control_deactivate(&wq.control); /* CLEANUP */ join_threads(); cleanup_structs(); }

  • C言語 勉強始めた所で、まだ良く解りません、教えてください!

    C言語 勉強始めた所で、まだ良く解りません、教えてください! このプログラムを実行すると、5,5と表示されると思うのですが? /*****************************************************************************/ #include <stdio.h> int average( int *data, int count ) { int i, sum=0; for( i=0; i<count; i++ ) sum+=data[i]; return sum/count; } int main(void) { int numbers [] = { 2, 3, 5, 7, 9, 11, 13, 15, 17,19 }; printf("%d\n",average(numbers,5)); return 0; } /*******************************************************************************/ 5、だけしか表示されません、これでよいのでしょうか?

  • 別ターミナルへのprintf出力

    LinuxでC言語プログラムから新しいターミナルを開き、そこにprintfで文字を出力したいのですがどうやったら良いのでしょうか?下記プログラムを作ってみましたが、新しいターミナルが開くだけで文字が出力されません #include <pthread.h> #include <stdio.h> #include <unistd.h> #include <signal.h> void* thread(void* arg) {  int pid=0;  pid = fork();  if(pid==0)  {    execlp("gnome-terminal","gnome-terminal",NULL);     printf("Hello World!!\n");  } } int main() {   pthread_t th;  void* result;   pthread_create(&th, NULL,thread, NULL);  pthread_join( th,&result); }

  • global変数をブロック内から参照したい

    可変長配列の可変長配列を飲み込んで 吐き出すコードです global変数 *st_memory こいつをブロック内から参照するには どない書けば良いのでしょうか 構造体とか他の関数から引っぱり出しても 何故にかSegmentation faultで弾かれます mallocとかgotoの処理は無視して下さい _________________________ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #define MAX 256 typedef enum{ SUCCESS, EOF_FILE, MEM_OVER }Add_List; char *st_memory = NULL; //global void free_buffer(void){ free(st_memory); st_memory = NULL; } Add_List add_char(const int ch,int *count){ static int buffer = 0; assert(buffer >= *count); if(buffer == *count){ st_memory = (char *)realloc(st_memory, (buffer + MAX) * sizeof(char)); if(st_memory == NULL)return MEM_OVER; buffer += MAX; }// END if st_memory[*count] = ch; (*count)++; return SUCCESS; } // END add_char(const int,int); Add_List read_line(FILE *fp,char **line){ int ch,used_line = 0; Add_List status = SUCCESS; while((ch = getc(fp)) != EOF){ if(ch == '¥n'){ status = add_char('¥0',&used_line); if(status != SUCCESS)goto FUNK_END; break; } // END if status = add_char(ch,&used_line);// MAIN if(status != SUCCESS)goto FUNK_END; }// END while if(ch == EOF){ if(used_line > 0){ status = add_char('¥0',&used_line); if(status != SUCCESS)goto FUNK_END; }else{ status = EOF_FILE; goto FUNK_END; } // END if } // END if line[0] = (char *)malloc(sizeof(char) * used_line); if(line[0] == NULL){ status = MEM_OVER; goto FUNK_END; } strcpy(line[0],st_memory);// MAIN FUNK_END: if(status != SUCCESS)free_buffer(); return status; }// END read_line(FILE *,char **); char ** add_line(char **text_file,char *mem_line, int *line_alloc_num,int *line_num){ assert(*line_alloc_num >= *line_num); if(*line_alloc_num == *line_num){ text_file = (char **)realloc(text_file, (*line_alloc_num + MAX) * sizeof(char)); if(text_file == NULL)exit(0); *line_alloc_num += MAX; } // END if text_file[*line_num] = mem_line; (*line_num)++; return text_file; } // END add_line(char **,char *,int *,int *); char ** read_file(FILE *fp,int *line_p){ char **text_file = NULL; int line_alloc_num = 0; int line_num = 0; char *mem_line = NULL; while(read_line(fp,&mem_line) == 0){ text_file = add_line(text_file, mem_line,&line_alloc_num,&line_num); } // END while text_file = (char **)realloc(text_file, line_alloc_num * sizeof(char)); if(text_file == NULL)exit(0); *line_p = line_num; return text_file; } // END read_file((FILE *,int *); int main(void){ char **text = NULL; int i,line_num = 0; text = read_file(stdin,&line_num); printf("¥n"); for(i=0;i<line_num;i++) printf("%s¥n",text[i]); return 0; } ______________________

  • 並列プログラミングのエラー

    6400×6400の行列のベクトル積を並列計算によって求め、その時間を計るプログラムです。 #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <pthread.h> #define MATRIX 6400 #define THREAD 2 #define COUNT 30 #define SPLIT 100 int INDEX = 0; double a[MATRIX * MATRIX], b[MATRIX], x[MATRIX]; pthread_mutex_t m1; double gettimeofday_sec() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + (double)tv.tv_usec*1e-6; } void thread_func(void *arg) { int i, j, tmp; while(INDEX < MATRIX) { pthread_mutex_lock(&m1); tmp = INDEX; INDEX += SPLIT; pthread_mutex_unlock(&m1); for(i = tmp; i < tmp + SPLIT; i++) { for(j = 0; j < MATRIX; j++) { b[i] += a[i * MATRIX + j] * x[j]; } } } } int main() { int i, j; double timeA, timeB; pthread_t handle[THREAD]; pthread_mutex_init(&m1, NULL); for(i = 0; i < MATRIX * MATRIX; i++) a[i] = rand() % 10; for(i = 0; i < MATRIX; i++) x[i] = rand() % 10; timeA = gettimeofday_sec(); //計測開始 for(i = 0; i < COUNT; i++) { for(j = 0; j < THREAD; i++) pthread_create(&handle[i], NULL, (void *)thread_func, NULL); for(j = 0; j < THREAD; i++) pthread_join(handle[i], NULL); INDEX = 0; } timeB = gettimeofday_sec(); //計測終了 printf("計算時間:%d\n", timeB - timeA); return 0; } cygwinでコンパイル、実行すると Exception: STATUS_ACCESS_VIOLATION at eip=00401276 eax=000018D0 ebx=000018FF ecx=00000003 edx=0022CE64 esi=611021A0 edi=004015E8 ebp=0022CCE8 esp=0022CC90 program=C:\cygwin\home\管理者\a.exe, pid 2020, thread main cs=001B ds=0023 es=0023 fs=003B gs=0000 ss=0023 Stack trace: Frame Function Args 0022CCE8 00401276 (00000001, 6116B690, 13F40090, 0022CC70) 0022CD98 610060D8 (00000000, 0022CDD0, 61005450, 0022CDD0) 61005450 61004416 (0000009C, A02404C7, E8611021, FFFFFF48) 7 [main] a 2020 _cygtls::handle_exceptions: Error while dumping state (probably corrupted stack) という内容のstackdumpファイルが生成されて実行できません。 どのように修正すればうまく実行できるでしょうか? 環境は OS:WindowsXP SP3 CPU:Intel(R) Core(TM)2 Duo E4500 @2.20GHz RAM:2048MB です。 よろしくお願いします。

  • c言語で文書を読み込み、単語の出現頻度を教える

    c言語の課題で、与えられた文書を読み込んでその中にある単語の出現頻度を教えるプログラミングを作成しているのですが、うまくいきません。 どこが間違っているのでしょうか?? ファイルの中身は As sweet as coat , green , milk And everyone think coat になっており、求めたい回答は buffer[0]=As count=1 buffer[1]=sweet count=1 buffer[2]=as count=1 buffer[3]=coat count=2 buffer[4]=green count=1 buffer[5]=milk count=1 buffer[6]=And count=1 buffer[7]=everyone count=1 buffer[8]=think count=1 Number of words:9 にしたいのです。 プログラミングは #include<stdio.h> #include<stdlib.h> #include<string.h> #include<ctype.h> typedef struct token_checker{ char * token; int count; }TOKEN_CHECKER; int main(int argc,char* argv[]){ FILE * fp; char buffer[1024]; int numword=0; char * delimiter = " .,"; char * s; TOKEN_CHECKER *t; int j; int i = 0; int flag =0; int find = -1; t=(TOKEN_CHECKER*)malloc(sizeof(TOKEN_CHECKER)*24); if(argc != 2){ printf("Parameter error.\n"); exit(1); } if((fp=fopen(argv[1],"r"))==NULL){ printf("File open error.\n"); exit(1); } while( fgets(buffer,sizeof(buffer),fp)!=NULL){ buffer[ strlen(buffer)-1]='\0'; s = strtok(buffer,delimiter); if(s != NULL){ t[numword].token=s; for(i=0;i<=numword;i++){ if(strcmp(t[numword].token,t[i].token)==0){ t[i].count++ } } printf("buffer[%d]=%s count=%d\n",numword,t[numword].token,t[numword].count); numword++; } while((s=strtok(NULL,delimiter)) != NULL){ t[numword].token=s; for(i=0;i<=numword;i++){ t[numword].count=0; if(strcmp(t[numword].token,t[i].token)==0){ t[i].count++; } } printf("buffer[%d]=%s count=%d\n",numword,t[numword].token,t[numword].count); numword++; } } printf("Number of words:%d\n",numword); free(t); fclose(fp); exit(0); } になっており、実行すると buffer[0]=As count=1 buffer[1]=sweet count=1 buffer[2]=as count=1 buffer[3]=coat count=1 buffer[4]=green count=1 buffer[5]=milk count=1 buffer[6]=And count=1 buffer[7]=everyone count=1 buffer[8]=think count=1 buffer[9]=coat count=1 Number of words:9 となってしまい、coatがカウントされないのです。

  • スレッドを2つ作って1秒ごとに2つのスレッドが数値を表示するプログラム

    スレッドを2つ作って1秒ごとに2つのスレッドが数値を表示するプログラムを作りたいのですがうまくいきません。 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<sys/socket.h> #include<arpa/inet.h> #include<unistd.h> #include<pthread.h> void *threadMain(void *threadArgs); int main(void) { int i = 0; pthread_t threadID; for(i = 0;i < 2;i++){ pthread_create(&threadID,NULL,threadMain,(void *)NULL); } } void *threadMain(void *threadArgs) { int i = 0; while(1){ printf("%d\n",++i); sleep(1); } } 上記プログラムを実行すると1が2回表示されて終了してしまいます。 どこか間違えがあるのでしょうか。。