Well, I'm starting my studies on POSIX threads in C, and I'm trying to make each thread, read a line of files, up to and well, I managed to make it work using a synchronization through the condition variable, but when reading the first line of the file, two threads can read at the same time causing the race conditions problem, why does this happen? I tested it using valgrind's helgrind tool.
#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;
}
Both threads are opening the file and assigning it to fp
.
After the first thread opens the file and reads the first entry, the next thread opens the file again and reads the first entry.
Fix this by opening the file in the main
function and passing the FILE *
as a parameter to the thread function. This also fixes the thread function by giving it a signature that pthread_create
expects, namely void *(*)(void *)
.
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;
}