簡體   English   中英

C中使用pthreads的競爭條件

[英]Race Conditions with pthreads in C

我是C語言中的新手,我正在編寫一個簡單的程序,可以並行查找多個文件中的單詞。 但是,每當我輸入多個文件時輸出會有所不同,這表明我的代碼中沒有修復競爭條件。 你能幫我解決一下嗎?

下面的代碼片段是main,是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打印與之后調用的同一調用不同的結果。 但請注意,只傳遞一個文件時程序才有效。

任何幫助表示贊賞。

這會導致未定義的行為,因為它超出了messagesthreads數組的末尾:

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);
} 

strtok保留一個全局的內部指針...使用strtok_r

為了避免每個線程的輸出以隨機方式混合在一起,您需要緩沖每個線程的輸出,然后一次顯示它們。

對於您的情況,最簡單的方法是將一個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() )可能是個好主意。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM