2016-03-21 7 views
0

このプログラムの目的は、マルチスレッドを使用して、単語のユーザー入力ワードで取り込まれた文字列をコピーすることです。各スレッドは4番目の単語をすべてコピーするので、最初のスレッドは1番目と5番目の単語をコピーし、2番目は2番目と6番目の単語をコピーします。私はmutexに関する研究をかなり行いました。しかし、文字列はまだ印刷されたときに混乱したナンセンスとして現れます。誰かがスレッドが同期していない理由についていくつかの光を当てることができますか?mutexを使ったPthread同期が正しく単語を同期しない

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

void *processString(void *); 

char msg1[100]; 
char msg2[100]; 
char * reg; 
char * token; 
char * tokens[10]; 
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t = PTHREAD_COND_INITIALIZER; 

int main(){ 
    int i = 0, j; 
    pthread_t workers[4]; 

    printf("Please input a string of words separated by whitespace characters: \n"); 
    scanf("%99[^\n]", msg1); //take in a full string including whitespace characters 

    //tokenize string into individual words 
    token = strtok(msg1, " "); 
    while(token != NULL){ 
     tokens[i] = (char *) malloc (sizeof(token)); 
     tokens[i] = token; 
     token = strtok(NULL, " "); 
     i++; 
    } 

    for(j = 0; j < 4; j++){ 
     if(pthread_create(&workers[j], NULL, processString, (void *) j)) 
      printf("Error creating pthreads"); 
    } 

    for(i = 0; i < 4; i++){ 
     pthread_join(workers[i], NULL); 
    } 
    pthread_mutex_destroy(&lock); 

    printf("%s\n", msg2); 

    return 0; 
} 

//each thread copies every fourth word 
void *processString(void *ptr){ 
    int j = (int) ptr, i = 0; 

    pthread_mutex_lock(&lock); 

    while(tokens[i * 4 + j] != NULL){ 
     reg = (char *) malloc (sizeof(tokens[i * 4 + j])); 
     reg = tokens[i * 4 + j]; 
     strcat(msg2, reg); 
     strcat(msg2, " "); 
     i++; 
    } 

    pthread_mutex_unlock(&lock); 
    return NULL; 
} 
+1

スレッドの実行順序を制御したい場合は、条件変数やセマフォのようなものが必要です。ミューテックスは、順序ではなく相互排除を保証します。 – EOF

+1

EOFが言ったこと。しかし、あなたのコードはメモリをリークします。そのループの各反復において、関数 'processString()'はメモリブロックを割り当て、そのブロックへのポインタを変数 'reg'に代入し、直ちにそのポインタを別のものに上書きして、割り当てられたポインタブロック。しかし、あなたは1つのポインタ*に十分なスペースを割り当てているので、ある意味ではそうですが、(間違った)意図はポインティングされた文字列に十分なスペースを割り当てることだったようです。 –

+1

また、ロックが間違っています。それぞれのスレッドがmutexを取得すると、それを解放する前にそのすべての作業を実行します。ミューテックスは、結果の文字列が壊れるのを防ぐのに効果的です。その意味では、正しく使用しています。しかし、入力に5単語未満がある場合にのみ、望ましい出力を得る機会があります。 –

答えて

1

@EOFはコメントで書いたように、ミューテックスはのみ相互排他を提供しています。それらは、複数の協調スレッドが同時に実行されるのを防ぎますが、スレッドによって獲得される順序を本質的に制御しません。さらに、私自身のコメントで説明したように、mutexes doは相互排除を提供します。あるスレッドがmutexを保持していれば、他のスレッドはそのmutexを取得できません。

スレッドを交代させるために直接提供するネイティブ同期オブジェクトはありません。結局のところ、スレッドがやりたいことではありません。あなたはセマフォを使ってそれを手配することができますが、スレッドを追加するとすぐに乱雑になります。非常にきれいな解決方法は、共有グローバル変数を使用して、実行するスレッドの順番を示すことです。その変数へのアクセスは、関連するすべてのスレッドが読み書きする必要があるため、mutexによって保護されている必要がありますが、問題があります:現在、mutexを保持しているスレッドは、

すべてのスレッドがループして、連続的にミューテックスを取得し、変数をテストし、ミューテックスを続行または解放することができます。残念ながら、そのようなビジー待機は非常にうまく実行されない傾向があります。一般に、実行中の任意の時点で進行可能なスレッドが一定時間内にミューテックスを取得することはできません。

ここではcondition variablesが入ります。条件変数は、停止していない別のスレッドによって判断される条件が満たされるまで、任意の数のスレッドがアクティビティを中断できるようにする同期オブジェクトです。このようなツールを使用すると、パフォーマンスが低下するため、ビジー待機が発生することがなくなり、すべてのスレッドが一定の時間内に実行できるようになります。次のように状態変数の汎用のスレッドごとの使用モデルは、次のとおり

  1. 私が進行することができるかどうかを
  2. テストを進めることができるか否かを判断することにより共有変数(複数可)を保護ミューテックスを取得します。もしそうなら、ステップ5にジャンプしてください。
  3. 今は進めません。条件変数の待機を実行します。
  4. 私は待ってから目を覚ましました。手順2に戻ります。
  5. 私がする必要がある作業を行います。
  6. 条件変数で待機しているすべてのスレッドをスリープ解除する信号をブロードキャストします。
  7. ミューテックスを解放します。

バリエーションは可能ですが、その理由を正確に把握していない限り、またバリエーションを念頭に置いた理由が安全であることを正確に知っている場合を除き、変更しないことをおすすめします。スレッドが与えられたmutexに関連付けられた条件変数で待機を実行すると、そのmutexを待っている間にそのmutexを自動的に解放し、waitから戻る前にそのmutexを自動的に解放することに注意してください。これにより、その間に他のスレッドを進めることができます。特に、同じ条件変数を待つことができます。

あなたの問題に当てはまるように、あなたのスレッドをテストする共有状態は、どのスレッドの順番を示している前述の変数であり、スレッドが待機する状態は、スレッドの順番です(ただし、これは条件変数の使用方法に暗黙のうちにあり、条件変数自体は一般的です)。これは、他のスレッドがどのスレッドの順番を更新するかを知らせる前に、各スレッドが行うべき作業の一部であることを意味することにも注意してください。そして、各スレッドは複数のターンを取る必要があるかもしれないので、プロシージャー全体をループで包む必要があります。

+0

ありがとう!それはまさに私が必要としたものでした。私のプログラムは、私が必要としていることを正確にやっています。 :) – Turbotec

関連する問題