[嗯,我开始研究C语言中的POSIX线程,我试图使每个线程读取一行文件,直到并且很好,我设法通过条件变量进行同步来使其正常工作。 ,但是在读取文件的第一行时,两个线程可以同时读取,从而导致竞争条件问题,为什么会发生这种情况?我使用valgrind的helgrind工具对其进行了测试。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
/*
$cat file.txt
test1
test2
test3
test4
test5
test6
*/
FILE *fp;
void *func(void) {
char c;
fp = fopen("file.txt", "r");
if(!fp) {
perror("DEBUG: ");
exit(EXIT_FAILURE);
}
pthread_mutex_lock(&mutex);
while((c = fgetc(fp)) != EOF) {
printf("TH = %zu CHARACTER = %c\n", pthread_self(), c);
if(c == '\n') {
pthread_cond_wait(&cond, &mutex);
} else {
pthread_cond_signal(&cond);
}
}
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
int main(void) {
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, (void *)func, NULL);
sleep(1);
pthread_create(&thread2, NULL, (void *)func, NULL);
pthread_join(thread2, NULL);
fclose(fp);
return 0;
}
[当线程输入func
时,它们都称为fp = fopen("file.txt", "r")
。这意味着从理论上讲,当FILE*
指向的fp
从首先运行的线程下拔出时,您可以在任何步骤读取文件。
如果每个线程都需要读取整个文件,则应将FILE *fp
声明拉到打开文件的位置,因此它是局部变量。如果采用这种方法,请确保同时关闭两个FILE*
。
如果他们应该共享当前设置的指针,那么您需要安全地打开文件。您可以根据需要通过两种方式完成此操作。
1)您应该更改声明,以将值也设置为NULL
。然后在func
内将pthread_mutex_lock(&mutex)
移至通话上方fopen()
。然后,仅在fopen()
时调用fp == NULL
。
2)您也可以在启动pthread之前将对fopen()
的调用移至main()
。这样一来,只有一个线程不必担心要打开文件,并且它与您的fclose(fp)
调用保持平衡,因此您知道fp
的范围是有效的指针。
此外,通常最好将所有线程都加入。如果您使用的是Valgrind,它将因为线程1未连接而抱怨线程1泄漏。对于这样的简单情况以及线程的行为,在这种情况下无关紧要,但是如果您正在学习pthread,那么从一开始就拥有一个好习惯。
两个线程都打开文件并从它们自己的FILE *
中读取。
在main
函数中打开文件,并将FILE *
作为参数传递给线程函数。
void *func(void *param) {
char c;
FILE *fp = param;
pthread_mutex_lock(&mutex);
while((c = fgetc(fp)) != EOF) {
printf("TH = %zu CHARACTER = %c\n", pthread_self(), c);
if(c == '\n') {
pthread_cond_wait(&cond, &mutex);
} else {
pthread_cond_signal(&cond);
}
}
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
int main(void) {
pthread_t thread1, thread2;
FILE *fp = fopen("file.txt", "r");
if(!fp) {
perror("DEBUG: ");
exit(EXIT_FAILURE);
}
pthread_create(&thread1, NULL, func, fp);
sleep(1);
pthread_create(&thread2, NULL, func, fp);
pthread_join(thread2, NULL);
fclose(fp);
return 0;
}