0

私は C で pthreads を初めて使用し、複数のファイル内の単語を並行して検索する単純なプログラムを作成しています。ただし、複数のファイルを入力するたびに出力が変化し、コードで修正していない競合状態があることを示唆しています。修正を手伝っていただけますか?

次のスニペットはメインで、pthreads を作成します。

    int i = 0;
char *word = "Pluto"; //Word to be found

Message messages[argc-1];
pthread_t threads[argc-1];
for(i; i < argc - 1; i++){
    messages[i].file = argv[i + 1];
    messages[i].word = word;
    messages[i].fp   = fopen(argv[i + 1], "r");
    int  iret = pthread_create( &threads[i], NULL, threadFindWord, (void*) &(messages[i]));
}for(i = 0; i < argc - 1; i++){
    pthread_join(threads[i],NULL);
}

各スレッドが呼び出す関数:

Message *msg;
msg = (Message *) ptr;

int numFound = ffindWord(msg->fp, msg->word);

printf("File %s has %i occurences of the word %s\n", msg->file, numFound, msg->word);

fclose(msg->fp);
pthread_exit(NULL);

以下は、ファイル内の単語を検索するためのコードです)

int findWord(char * file, char * word){
 char * current = strtok(file, " ,.\n");
 int sum = 0;
 while (current != NULL){
    //printf("%s\n", current);
    if(strcmp(current, word) == 0)
        sum+=1;
    current = strtok(NULL, " ,.\n");
}
return sum;
}



int ffindWord(FILE *fp, char *word){

 fseek(fp, 0, SEEK_END);
 long pos = ftell(fp);
 fseek(fp, 0, SEEK_SET);
 char *bytes = malloc(pos);
 fread(bytes, pos, 1, fp);
 bytes[pos-1] = '\0';

 int sum = findWord(bytes, word);

 free(bytes);
 return sum;
 }

明確にするために、問題は、プログラムを連続して実行すると異なる結果が得られることです。呼び出し $programname file1 file2 は、直後に呼び出された同じ呼び出しとは異なる結果を出力します。ただし、プログラムは 1 つのファイルのみが渡された場合に機能することに注意してください。

どんな助けでも大歓迎です。

4

3 に答える 3

1

messagesこれにより、配列と配列の終わりを超えると、未定義の動作が発生しthreadsます。

Message messages[argc-1];
pthread_t threads[argc-1];
for(i; i < argc; i++){

し、トラブルの原因となることがあります。1スレッドしか実行されていない場合、たまたま動くかもしれません。

(または同様のもの) に変更してみてください:

int i;
Message messages[argc-1];
pthread_t threads[argc-1];
for(i = 1; i < argc; i++)
{
    messages[i - 1].file = argv[i];
    messages[i - 1].word = word;
    messages[i - 1].fp   = fopen(argv[i], "r");
    int iret = pthread_create(&threads[i - 1],
                               NULL,
                               threadFindWord,
                               (void*)&(messages[i - 1]));
}

for(i = 0; i < argc - 1; i++)
{
    pthread_join(threads[i],NULL);
} 
于 2012-05-11T10:49:06.227 に答える
1

strtok は、グローバルな内部ポインターを保持します... strtok_rを使用します。

于 2012-05-11T20:03:32.053 に答える
0

各スレッドからの出力が無作為に混ざり合わないようにするには、各スレッドの出力をバッファリングしてから、一度に 1 つずつ表示する必要があります。

あなたの場合、これを行う最も簡単な方法は、char *thread_outputフィールド(およびthread_output_sizeフィールド)をMessage構造体に追加し、メインスレッドで次のようにすることです。

for(i = 0; i < argc - 1; i++)
{
    pthread_join(threads[i],NULL);
    printf("%s", messages[i - 1].thread_output);
}

thread_outputおそらく、バッファが十分な大きさであることを確認し、 を使用vsnprintf()して新しいテキストをバッファに追加する関数を実装したいと思うでしょうprintf()

例えば:

void add_thread_output(int thread_number, const char *template, ...) {
    int old_length;
    int length;
    char *temp;

    va_start(ap, template);
    length = vsnprintf(NULL, 0, template, ap);
    va_end(ap);

    old_length = messages[thread_number - 1].thread_output_size;
    temp = realloc(messages[thread_number - 1].thread_output, old_length + length + 1);
    if(temp == NULL) {
        /* Set a flag or something */
    } else {
        va_start(ap, template);
        vsnprintf(&temp[old_length], length + 1, template, ap);
        va_end(ap);
        messages[thread_number - 1].thread_output_size += length;
        messages[thread_number - 1].thread_output = temp;
    }
}

注: 上記のコード例は、例のみを目的としており、コンパイルや動作がテストされておらず、保証されていません。また、必ずしも最も効率的な方法であるとは限りません。たとえば、必要以上のスペースを割り当てること (realloc()スレッドの出力バッファーに何かを追加するたびに行うことを避けるため) は良い考えかもしれません。

于 2012-05-11T11:43:23.427 に答える