3 Потоки и проблема Consumer-Producer с семафорами - PullRequest
2 голосов
/ 02 апреля 2020

поток параллелизма newb ie здесь. Итак, у меня есть проблема, когда мой encrypt_thread иногда зависает, и я почти уверен, что это из-за того, как я использовал свои семафоры.

Что делает моя программа :

  1. read_from_file - это поток, который читает символы из файла в input_buffer по одному символу за раз. Каждый раз, когда это происходит, он уменьшает empty_in_input_buffer на 1 и увеличивает full_in_input_buffer на 1. Если empty_in_input равен 0, он ожидает сообщения (& empty_in_input_buffer) из потока Encrypt.

  2. Поток шифрования ожидает сообщения (& full_in_input_buffer) из потока Read, чтобы начать шифрование символа. Затем он вызывает post (& empty_in_input_buffer) и затем wait (& empty_in_output_buffer) . Как только он помещает зашифрованный символ в output_buffer, он вызывает post (& empty_in_output_buffer) . Encrypt - это «посредник», ожидающий размещения нового символа в input_buffer и освобождения нового слота в output_buffer.

  3. Запись потоковых вызовов wait ( & full_in_output_buffer) чтобы затем возобновить выполнение и записать символ в output_buffer в файл. После этого он вызывает post (& empty_in_output_buffer) .

Я хочу достичь максимального параллелизма, чтобы, если read_from_file поместил новый символ в слот 5 input_buffer, затем encrypt может по-прежнему обращаться к слотам 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);
    }

}

1 Ответ

1 голос
/ 03 апреля 2020

Вы не опубликовали полную, воспроизводимую программу, поэтому предположите: 1) вы сомнительно используете EOF. Условно вы видите возврат get c как int; это может охватывать все допустимые значения символов, а также EOF. Это также защищает вас от компиляторов, которые считают, что неподписанные символы являются разумным значением по умолчанию. В любом случае, вам, вероятно, следует выбрать другое часовое значение для прохождения через ваши буферы, чтобы указать EOF.

in:

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

2) Поскольку вы задаете ему отрицательное значение (EOF) будет усечен до (char) -1), поэтому, если вы используете его в качестве индекса, вы можете получить некоторые неожиданные значения.

3) Если ваш encrypt_letter сгенерирует 0xff в качестве зашифрованной версии, он будет интерпретироваться этим и последними этапами как EOF; но на первом этапе все еще будет пытаться счастливо читать символы.

Резюме: EOF - это не символьное значение, а int.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...