3个带有信号量的线程和消费者生产者问题

问题描述 投票:2回答:1

这里是线程并发新手。因此,我有一个问题,我的crypto_thread有时会挂起,我很确定这是因为我使用了信号灯的方式。

我的程序做什么

  1. read_from_file是一个线程,一次将一个文件中的字符读取到input_buffer中的一个字符。每次执行此操作时,它将empty_in_input_buffer减小1,并将full_in_input_buffer增大1。如果empty_in_input为0,它将等待来自Encrypt线程的post(&empty_in_input_buffer)] >>。

  2. 加密线程等待读取线程中的post(&full_in_input_buffer))>>开始对字符进行加密。然后,它调用post(&empty_in_input_buffer)

  3. ,然后调用wait(&empty_in_output_buffer)。将加密的字符放入output_buffer后,它将调用post(&empty_in_output_buffer)。加密是“中间人”,它等待将新字符放入input_buffer中,并等待output_buffer中的新插槽可用。
  4. 写线程调用wait(&full_in_output_buffer)

    ,然后恢复执行,并将output_buffer中的字符写入文件。完成后,它将调用post(&empty_in_output_buffer)
  5. 我想实现最大的并发性,因此,如果read_from_file在input_buffer的插槽5中放置了一个新字符,那么加密仍可以访问插槽3和4进行加密并写入到output_buffer中。我没有使用互斥锁来锁定input_buffer,因为缓冲区中的项没有被修改,只能读取,加密并放置到output_buffer中,但是我可能不需要这样的假设,这可能是错误的。

    该程序还在开始时提示用户输入buffer_size。问题是,我的程序挂起一半时间,而另一半完全正常运行,这表明我处于无法解决的竞争状态。但是,我一直无法弄清楚它发生在哪里。

编辑:fill_letter_arr仅创建大写和小写字母的字符数组。 is_in_letters仅检查字符是否为字母中的字母。我的加密非常简单,只加密字母。

主线程:

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);
    }

}

这里是线程并发新手。因此,我有一个问题,我的crypto_thread有时会挂起,我很确定这是因为我使用了信号灯的方式。我的程序做什么:...

c multithreading concurrency semaphore
1个回答
0
投票

您没有发布完整的,可复制的程序,所以猜测:1)您怀疑使用EOF。按照惯例,您将getc的返回视为int;它可以覆盖每个有效字符值以及EOF。这也可以保护您免受认为无符号字符是合理默认值的编译器的侵害。无论如何,您可能应该选择其他警戒值来通过缓冲区以指示EOF。

in:

© www.soinside.com 2019 - 2024. All rights reserved.