So I'm doing this Uni exercise and the main task is to make a program that creates a process for every file and for every file with a dynamic way we create n number of threads and every thread is counting a number of words with some logic, so my problem is that I need to make sure the thread with the index of NTHREADS-1 is going to finish last. By reading the book we have for this Course I came across something that was saying ".....we can make a thread wait for another/others to finish one job and then give it time in the CPU to do its job....". So made an if statement that checks if this is the thread with the index of NTHREADS-1(last one), and if it is, it enters a 'for' loop in which waits for the other NTHREADS-2 threads to finish and then continue, but when I compiled it I got nothing at the output, which normally prints letters and then noticed that the last thread never continues and never return to the main function the control to which I had another pthread_join()
. Can someone explain what I'm missing, I do not want to solve the exercise for me just to tell me what I understood wrong. This is the code that I'm experimenting with, here I'm not implementing it with a dynamic number of threads, I'm trying to do it with a static number first.
int main(int argc, char *argv[]) {
signal(SIGINT, catcher);
signal(SIGTERM, catcher);
DIR *folder;
struct dirent *entry;
int files = 0, dfd;
struct stat statbuf;
int count = 0, ffd;
off_t foff;
if (argc < 2) {
//current directory.
if ((folder = fdopendir((dfd = open(".", O_RDONLY)))) == NULL) {
fprintf(stderr, "Cannot open directory
");
exit(1);
}
} else {
if ((folder = fdopendir((dfd = open(argv[1], O_RDONLY)))) == NULL) {
fprintf(stderr, "Cannot open directory
");
exit(1);
}
}
if (folder == NULL) {
fprintf(stderr, "Error : Failed to open common_file - %s
", strerror(errno));
return (1);
}
while ((entry = readdir(folder))) {
//each child we want it to have its own total word sum.
files++;
/* On linux/Unix we don't want current and parent directories
* If you're on Windows machine remove this two lines
* also we do not want to look at hidden files.
*/
if (entry->d_name[0] == 46)
continue;
/* there is a possible race condition here as the file
* could be renamed between the readdir and the open */
if (entry->d_type != DT_REG)
continue;
//opening the file to read with openat(), same as open
if ((ffd = openat(dfd, entry->d_name, O_RDONLY)) == -1) {
perror(entry->d_name);
abort();
}
//checking if it is an executable file.
if (fstat(ffd, &statbuf) == 0 && !(statbuf.st_mode & S_IXUSR)) {
//Find how many characters are in this file.
if ((foff = lseek(ffd, 0, SEEK_END)) == -1) {
printf("There was an error");
abort();
}
if (foff == 0) {
//is the file does not have any characters inside it.
printf("This file %s contains no words.
", entry->d_name);
continue;
}
if ((isASCII(ffd, foff)) != 0) {
printf("The file with name: %s and size of %ld is not an ascii file", entry->d_name, foff);
}
//reset the "needle" at the start of the file because we moved it with the last if.
lseek(ffd, 0, SEEK_SET);
if (fork() == 0) {
pthread_t threads[NTHREADS];
data th[NTHREADS];
for (int i = 0; i < NTHREADS; ++i) {
th[i].tnum = i;//keeping the threads number
th[i].foff = foff;//kepping the total count of chars in the file.
th[i].ffd = ffd;//keeping the file descripton in order to open if latter a any thread with the right offset.
th[i].entry = entry;
th[i].dfd =dfd;
th[i].threads[i] = threads[i];
pthread_create(&threads[i], NULL, &thread_func, (void *) &th[i]);
}
/*waiting for the last thread to finis, since this one is waiting for the other n-1 threads.and since we start from the zero the
last thread will have an index of n-1 also, DO NOT GET CONFUSED THE ELEMENT WITH INDEX OF n-1 IS THE LAST ELEMENT
INSIDE THE ARRAY BUTT THE n-1 ELEMENT IS THE ELEMENT WITH INDEX OF n-2*/
pthread_join(threads[NTHREADS-1], NULL);
printf("%d, %s, %d
",getpid(), entry->d_name, sum);
exit(0);
}
}
}
//Parent is waiting for all of his children to finish
for (int i = 0; i <= files; i++) // loop will run files times how many files we counted inside the loop
wait(NULL);
closedir(folder);
}
The function every thread is calling when is being created.
void * thread_func(void *th) {
/* seting each threads stack with the right variables from the process is beeing called from */
data *td = th;
int limit = td->tnum;
int partialsum = 0,ffd;
unsigned char c;
if (td->tnum == NTHREADS - 1 && td->foff%NTHREADS != 0){
for (int i = 0; i < NTHREADS-1; ++i) {
pthread_join(td->threads[i], NULL);
}
for (long i = limit * (td->foff / NTHREADS); i < (limit + 1) * (td->foff / NTHREADS) + (td->foff%NTHREADS); i++){
read(td->ffd, &c, 1);
partialsum += 1;
printf("%c",c);
}
} else {
for (long i = limit * (td->foff / NTHREADS); i < (limit + 1) * (td->foff / NTHREADS); i++) {
read(td->ffd, &c, 1);
partialsum += 1;
printf("%c",c);
}
}
pthread_mutex_lock(&mymutex);
sum += partialsum;
pthread_mutex_lock(&mymutex);
pthread_exit(NULL);
}
and the struct that is defined at a header file.
typedef struct t_data data;
struct t_data{
int tnum,ffd,dfd;
off_t foff;
struct dirent *entry;
pthread_t threads[NTHREADS];
} ;
question from:
https://stackoverflow.com/questions/65875259/one-thread-waiting-n-others-to-finish-in-c