[英]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打印與之后調用的同一調用不同的結果。 但請注意,只傳遞一個文件時程序才有效。
任何幫助表示贊賞。
這會導致未定義的行為,因為它超出了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);
}
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.