Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
169 views
in Technique[技术] by (71.8m points)

multithreading - One thread waiting n others to finish in C

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...