Проблема читателей-писателей - предпочтение писателей (читатели могут голодать) - PullRequest
0 голосов
/ 11 июня 2019

У меня проблема с читателями-писателями. Я хочу, чтобы авторы высказались за решение с использованием мьютекса. Пока я написал это

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <memory.h>
#include <stdbool.h>
#include <stdint.h>
#include<unistd.h>

int NO_READERS;
int NO_WRITERS;
int NO_READERS_READING = 0;     // How many readers need shared resources
int NO_WRITERS_WRITING = 0;     // How many writers need shared resources

pthread_mutex_t resourceMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t tryResourceMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t readerMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t writerMutex = PTHREAD_MUTEX_INITIALIZER;

void *readerJob(void *arg) {
    int *id = (int*)arg;
    while (1) {
        pthread_mutex_lock(&tryResourceMutex); // Indicate reader is trying to enter
        pthread_mutex_lock(&readerMutex);
        NO_READERS_READING++; // Indicate that you are needing the shared resource (one more reader)
        if (NO_READERS_READING == 1) {
            pthread_mutex_lock(&resourceMutex);
        }
        pthread_mutex_unlock(&readerMutex);
        pthread_mutex_unlock(&tryResourceMutex);
         printf("READER ID %d WALKED IN \n",*id);
        printf("ReaderQ: %d , WriterQ: %d [in: R:%d W:%d]\n",
                NO_READERS - NO_READERS_READING,
                NO_WRITERS - NO_WRITERS_WRITING,
                NO_READERS_READING,
                NO_WRITERS_WRITING);
        sleep(1);
        pthread_mutex_lock(&readerMutex);
        NO_READERS_READING--;
        if (NO_READERS_READING == 0) { // Check if you are the last reader
            pthread_mutex_unlock(&resourceMutex);
        }
        pthread_mutex_unlock(&readerMutex);
    }
    return 0;
}

void *writerJob(void *arg) {
    int *id = (int*)arg;
    while (1) {
        pthread_mutex_lock(&writerMutex);
        NO_WRITERS_WRITING++;
        if (NO_WRITERS_WRITING == 1) {
            pthread_mutex_lock(&tryResourceMutex); // If there are no other writers lock the readers out
        }
        pthread_mutex_unlock(&writerMutex);

        pthread_mutex_lock(&resourceMutex);
        printf("WRITER ID %d WALKED IN \n",*id);
        printf("ReaderQ: %d , WriterQ: %d [in: R:%d W:%d]\n",
                NO_READERS - NO_READERS_READING,
                NO_WRITERS - NO_WRITERS_WRITING,
                NO_READERS_READING,
                NO_WRITERS_WRITING);
        sleep(1);
        pthread_mutex_unlock(&resourceMutex);

        pthread_mutex_lock(&writerMutex);
        NO_WRITERS_WRITING--;
        if (NO_WRITERS_WRITING == 0) {
            pthread_mutex_unlock(&tryResourceMutex); // If there are no writers left unlock the readers
        }
        pthread_mutex_unlock(&writerMutex);
    }
    return 0;
}

int main(int argc, char *argv[]) {
    NO_READERS = atoi(argv[1]);
    NO_WRITERS = atoi(argv[2]);

    // Initialize arrays of threads IDs
    pthread_t *readersThreadsIds = malloc(NO_READERS * sizeof(pthread_t));
    pthread_t *writersThreadsIds = malloc(NO_READERS * sizeof(pthread_t));

    // Initialize shared memory (array) with random numbers

    // Create readers threads
    for (int i = 0; i < NO_READERS; ++i) {
        int* id = (int*)(malloc(sizeof(int)));
        *id = i;
        pthread_create(&readersThreadsIds[i], NULL, readerJob,(void*)id);
    }
    // Create writers threads
    for (int i = 0; i < NO_WRITERS; ++i) {
        int* id = (int*)(malloc(sizeof(int)));
        *id = i;
        pthread_create(&writersThreadsIds[i], NULL, writerJob, (void*)id);

    }

    // Wait for readers to finish
    for (int i = 0; i < NO_READERS; ++i) {
        pthread_join(readersThreadsIds[i], NULL);
        }
    // Wait for writers to finish
    for (int i = 0; i < NO_WRITERS; ++i) {
        pthread_join(writersThreadsIds[i], NULL);
    }

    free(readersThreadsIds);
    free(writersThreadsIds);
    pthread_mutex_destroy(&resourceMutex);
    pthread_mutex_destroy(&tryResourceMutex);
    pthread_mutex_destroy(&readerMutex);
    pthread_mutex_destroy(&writerMutex);
    return 0;
}

И я не уверен, должно ли это работать так. Кто-нибудь может проверить это для меня? Я хочу получить информацию о том, какой читатель или писатель входит или выходит. Кажется, что он застрял в какой-то момент, но я не знаю почему.

Ответы [ 2 ]

1 голос
/ 11 июня 2019

Кажется, ты делаешь то, что хочешь, то есть отдаешь предпочтение писателям.Потому что ваши потоки зацикливаются на получении и снятии блокировки;если у вас есть более одного автора, авторы будут по очереди передавать его между собой и голодать читателей.То есть каждый раз, когда кто-то освобождает resourceMutex, его ожидает другой писатель, поэтому NO_WRITERS_WRITING никогда не достигнет нуля.

Чтобы увидеть, как он работает, как задумано, добавьте задержку в верхней части цикла while каждогопоток:

usleep ((rand ()% 10000) * 10000);

Это позволит читателям периодически получать доступ, когда все авторы находятся в usleep ().

0 голосов
/ 11 июня 2019

В начале все читатели приходят,

Под "входом" я понимаю, что вы выполняете вызовы printf() в цикле readerJob.Неудивительно, что все читатели приходят первыми, потому что вы запускаете их первыми, и в вероятном случае, когда первый поток читателей, пытающийся заблокировать tryResourceMutex, делает это раньше, чем любой поток записывающего устройства, он затем блокирует resourceMutex(),также, предотвращая "вход" любого автора. Но то, что не не мешает авторам увеличивать NO_WRITERS_WRITING. И это также не мешает одному из них заблокировать tryResourceMutex и удерживать его заблокированным.

sleep() вызов в читателе будет (вероятно) заставлять resourceMutex удерживаться непрерывно достаточно долго, чтобы все читатели приходили раньше, чем кто-либо из авторов, так как каждый писатель должен получить resourceMutex, чтобы войти.

затем также писатели, которые не должны быть возможны в то же время.

Я не вижу этого в моих тестах.Но я делаю вижу то, что я уже описал: счетчик писателей увеличивается с нуля, даже если им запрещено входить, когда внутри читатели.По сути, имя вашей переменной NO_WRITERS_WRITING не соответствует вашему фактическому использованию - указывает, сколько писателей пишут или ожидают записи .

Когда читатели уходят, они блокируются отвозвращаясь сразу же, потому что один из авторов держит tryResourceMutex.В конце концов, последний читатель выйдет и выпустит resourceMutex.Это позволит авторам продолжать работу по одному, но с вызовом sleep(), расположенным там, где он находится в цикле записи, крайне маловероятно, что число авторов когда-либо упадет до нуля, чтобы любой из читателей могповторный ввод.Однако если это произойдет, то, скорее всего, тот же цикл повторится: все читатели будут входить один раз, а все писатели стоят в очереди.

Тогда все читатели исчезнут, но их большеодин писатель одновременно в библиотеке.

Опять нет.Только один писатель находится внутри, но остальные большую часть времени стоят в очереди, так что NO_WRITERS_WRITING почти всегда будет равно NO_WRITERS.

Суть в том, что вы запутались.Вы используете переменную NO_WRITERS_WRITING главным образом для представления числа писателей, которые готовы к записи, но ваша система обмена сообщениями использует ее так, как если бы это было число, которое фактически пишет.То же самое не относится к NO_READERS_READING, потому что как только поток получает мьютекс, необходимый для изменения этой переменной, ничто иное не мешает ему войти в комнату.

Еще одна вещь: сделать симуляцию интересной -т. е. чтобы не дать авторам возможности получить постоянный контроль - вы должны ввести задержку, желательно случайную, после того, как каждый поток покидает комнату, прежде чем он попытается повторно войти.И задержка для писателей, вероятно, должна быть значительно больше, чем задержка для читателей.

...