簡體   English   中英

在多個線程上使用 pthread_join() 會產生意外行為

[英]Using pthread_join() on multiple threads giving unexpected behavior

我正在學習如何在 C 中使用線程,並且在創建線程時遇到了問題。 我正在制作一個程序,它以 2 個或多個文件名作為命令行 arguments,計算每個文件在各自線程中的字節數,然后輸出最大文件的名稱。 當我在創建線程后直接使用 pthread_join() 時,程序按預期運行。 但是,我知道這不是線程應該使用的方式,因為它違背了目的。 當我在創建所有線程后在 for 循環中使用 pthread_join() 時,程序無法正常工作。 誰能告訴我我做錯了什么? 感謝所有幫助。 這是我的主要 function。

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //mutex for changing max_bytes and max_name
int max_bytes = 0;
char max_name[100];

struct arg_struct{ //struct to hold args to pass the threads
        int fd;
        char name[100];
};

int main(int argc, char* argv[])
{
        if(argc < 3){ //checks for correct number of arguments passed
                perror("Wrong number of arguments");
                return EXIT_FAILURE;
        }

        int arg_num = argc - 1; //holds number of arguments passed

        pthread_t threadid[arg_num]; //array of thread IDs
        struct arg_struct args;
        for(int i = 0; i < arg_num; i++){
                args.fd = open(argv[i+1], O_RDONLY);
                memcpy(args.name, argv[i+1], sizeof(args.name)); //copies file name into arg_struct
                int thread_err = pthread_create(&threadid[i], NULL, count_bytes, (void*)&args); //create thread by calling count_bytes and passing it a struct of args
                //pthread_join(threadid[i], NULL);
                if(thread_err != 0){
                        perror("pthread_create failed");
                        return EXIT_FAILURE;
                }
        }

        for(int i = 0; i < arg_num; i++){
                pthread_join(threadid[i], NULL);
        }

        printf("%s is the largest of the submitted files\n", max_name);

        return 0;
}

這是線程正在運行的 function。

void *count_bytes(void* arguments)
{
        struct arg_struct *args = (struct arg_struct*)arguments; //casting arguments back to struct from void*
        int fd = args -> fd;
        char name[100];
        memcpy(name, args -> name, sizeof(name)); //copies file name into name from args.name
        int bytes = 0;

        int size = 10;
        char*  buffer = (char*) malloc(size);
        if(buffer == NULL){
                perror("malloc failed");
                exit(EXIT_FAILURE);
        }
        int buffer_count = 0;
        for(int i = 0; i < size; i++){
                buffer[i] = '\0'; //sets all elements to '\0' to determine end of file later
        }
        int read_return = read(fd, &buffer[buffer_count], 1);
        if(read_return == -1){
                perror("reading failed");
                exit(EXIT_FAILURE);
        }

        while(buffer[buffer_count] != '\0'){
                bytes++;
                buffer_count++;
                buffer[buffer_count] = '\0'; //sets previous element to '\0' to determine end of file later
                if(buffer_count >= size){
                        buffer_count = 0; //buffer will hold up to 10 elements and then go back to the beginning
                }
                read_return = read(fd, &buffer[buffer_count], 1);
                if(read_return == -1){
                        perror("reading failed");
                        exit(EXIT_FAILURE);
                }
        }

        printf("%s has %d bytes\n", name, bytes);

        pthread_mutex_lock(&mutex);
        if(bytes > max_bytes){
                max_bytes = bytes;
                memcpy(max_name, name, sizeof(max_name));
        }
        //locks mutex to avoid race condition
        //then sets bytes to max_bytes if it is later than max_bytes
        //then locks mutex to allow another thread to have access
        pthread_mutex_unlock(&mutex);

        return NULL;
}

如果它有任何用處,這是它正確運行時產生的兩個輸出

./a.out another buffered_readword.c
another has 8 bytes
buffered_readword.c has 3747 bytes
buffered_readword.c is the largest of the submitted files

而且不正確

./a.out another buffered_readword.c
buffered_readword.c has 1867 bytes
buffered_readword.c has 1881 bytes
buffered_readword.c is the largest of the submitted files

問題是只有一個args結構。 調用pthread_create后,新線程可能不會立即運行。 到線程運行時,它們很可能都會看到相同的args值。 在線程創建循環中調用pthread_join “修復”了該問題,因為它確保每個線程在args更新為下一個值之前完成。

要正確修復,將不同的args傳遞給每個線程。 執行此操作的說明性代碼:

struct arg_struct args[arg_num];
for(int i = 0; i < arg_num; i++){
    args[i].fd = open(argv[i+1], O_RDONLY);
    memcpy(args[i].name, argv[i+1], sizeof(args[i].name));
    int thread_err = pthread_create(&threadid[i], NULL, count_bytes, &args[i]); 
    ....

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM