C 3线程和消费者-生产者信号量问题

C 3线程和消费者-生产者信号量问题,c,multithreading,concurrency,semaphore,C,Multithreading,Concurrency,Semaphore,线程并发新手在这里。因此,我的encrypt_线程有时会挂起,我很确定这是因为我使用信号量的方式 我的程序的功能: read_from_file是一个线程,它将文件中的字符一次读取一个字符到输入缓冲区。每次这样做时,它会将\u输入\u缓冲区中的空\u减少1,并将\u输入\u缓冲区中的满\u增加1。如果\u input中的empty\u为0,则它将等待来自加密线程的post(&empty\u input\u buffer) 加密线程等待来自读取线程的post(&full_in_input_buff

线程并发新手在这里。因此,我的encrypt_线程有时会挂起,我很确定这是因为我使用信号量的方式

我的程序的功能

  • read_from_file是一个线程,它将文件中的字符一次读取一个字符到输入缓冲区。每次这样做时,它会将\u输入\u缓冲区中的空\u减少1,并将\u输入\u缓冲区中的满\u增加1。如果\u input中的empty\u为0,则它将等待来自加密线程的post(&empty\u input\u buffer)

  • 加密线程等待来自读取线程的post(&full_in_input_buffer)开始字符加密。然后它调用post(&empty_in_input_buffer),然后等待(&empty_in_output_buffer)。一旦将加密字符放入输出缓冲区,它将调用post(&empty\u in\u output\u buffer)。Encrypt是“中间人”,等待一个新字符被放入输入缓冲区,并等待一个新的插槽在输出缓冲区中空闲

  • 写入线程调用等待(&full_in_output_buffer)然后恢复执行,并将输出_buffer中的字符写入文件。一旦完成,它将调用post(&empty\u in\u output\u buffer)

  • 我希望实现最大的并发性,这样,如果从_文件中读取_是在输入_缓冲区的插槽5处放置一个新字符,那么encrypt仍然可以访问插槽3和4来加密和写入输出_缓冲区。我没有使用互斥锁来锁定输入缓冲区,因为缓冲区中的项目没有修改,只是读取、加密并放入输出缓冲区,但我可能错误地认为我不需要

    该程序还在开始时提示用户输入缓冲区大小。问题是,我的程序有一半的时间是挂起的,另一半的时间运行得很好,这表明我有一个我没有考虑的比赛条件。然而,我一直无法弄清楚它发生在哪里

    编辑:fill_letter_arr只是创建一个大写和小写字母的字母表字符数组。is_in_字母只是检查字符是否是字母表中的字母。我的加密非常简单,它只加密字母

    主线程:

    int main(int argc, char *argv[]){
        //sem_init(&encrypt_signals_read, 0, 1); 
        int buf_size;
        file_in = fopen(argv[1], "r");
        file_out = fopen(argv[2], "w");
    
        take_input(&buf_size);
    
        struct thread_args args = {
            malloc(sizeof(char)*buf_size),
            malloc(sizeof(char)*buf_size),
            buf_size,
            0,
        };
    
        sem_init(&empty_in_input,0,buf_size); 
        sem_init(&empty_in_output,0,buf_size);
        sem_init(&full_in_input_buffer,0,0);
        sem_init(&full_in_output_buffer,0,0);
    
        //creating threads
        pthread_t read_thread,encrypt_thread,write_thread; 
    
        if(pthread_create(&read_thread,NULL,read_from_file,&args) != 0){
            printf("Error creating read thread!");
        }
        if(pthread_create(&encrypt_thread,NULL,encrypt,&args) != 0){
            printf("Error creating encrypt thread!");
        }
        if(pthread_create(&write_thread,NULL,write_to_file,&args) != 0){
            printf("Error creating write thread!");
        }
    
        pthread_join(read_thread,NULL);
        pthread_join(encrypt_thread,NULL);
        pthread_join(write_thread,NULL);
    
        fclose(file_in);
        fclose(file_out);
    }
    
    读线程:

    void* read_from_file(void* args){
        struct thread_args* shared = (struct thread_args*) args;
        char c = '0';
        int i = 0;
        int val,val1,val2,val3;
        if (file_in != NULL){
    
            do{
    
                c = fgetc(file_in);
    
                if(i >= shared->buffer_size)
                    i = 0;
    
                sem_wait(&empty_in_input);
                shared->input_buffer[i] = c;
                sem_post(&full_in_input_buffer);
                i++;
    
            }while(c != EOF);
    
        }
         if (ferror(file_in) != 0 ) {
                fputs("Error reading file", stderr);
                exit(1);
        }
    }
    
    加密线程:

    void* encrypt(void* args){
        struct thread_args* shared = (struct thread_args*) args;
        int s = 1;
        int i = 0;
        char c = '0';
        int val,val1,val2,val3,val4;
    
    
    
        fill_letters_arr(0);
    
        do{
    
            if(i >= shared->buffer_size)
                i = 0;
    
            sem_wait(&full_in_input_buffer);
            c = shared->input_buffer[i];
            sem_post(&empty_in_input);
    
            if(is_in_letters(&c) == true){
                encrypt_letter(&s,&c);
            }
    
            sem_wait(&empty_in_output);
            shared->output_buffer[i] = c;
            sem_post(&full_in_output_buffer);
            i++;
    
        }while(c != EOF);
    }
    
    写入线程:

    void* write_to_file(void* args){
        struct thread_args* shared = (struct thread_args*) args;
        char c = '0';
        int i = 0;
        int val,val1,val2,val3;
    
    
        if (file_out != NULL){
    
            while(c != EOF){
    
                if(i >= shared->buffer_size)
                    i = 0;
    
                sem_wait(&full_in_output_buffer);
                c = shared->output_buffer[i];
                fputc(c,file_out);
                sem_post(&empty_in_output);
                i++;
            }
    
        }
         if (ferror(file_in) != 0 ) {
                fputs("Error reading file", stderr);
        }
    
    }
    

    您没有发布完整的、可复制的程序,因此猜测: 1) 你有一个可疑的使用EOF。按照惯例,您将getc的返回视为int;这可以覆盖所有有效字符值以及EOF。这还可以防止编译器认为未签名字符是合理的默认值。无论如何,您可能应该选择一个不同的sentinal值来通过缓冲区来指示EOF

    在:

    2) 因为您给它一个负值(EOF将截断为(char)-1),所以如果您将它用作索引,您可能会得到一些令人惊讶的值

    3) 如果您的加密信碰巧生成了一个0xff作为加密版本,那么它将被此和最后阶段解释为EOF;但第一阶段仍将尝试愉快地阅读文字

    概述:EOF不是字符值,它是int

    if(is_in_letters(&c) == true){
        encrypt_letter(&s,&c);
    }