读者-作家问题作家-偏好(读者可能会饿死)

时间:2019-06-11 16:02:55

标签: c pthreads mutex thread-synchronization

我有读者-作家问题。我想写一些使用互斥锁的解决方案。到目前为止,我已经写了这个

#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 个答案:

答案 0 :(得分:1)

它似乎在做您想做的事,那就是优先考虑作家。因为您的线程循环获取和释放锁;如果您有一位以上的作家,那么作家将轮流在彼此之间传递,并使读者挨饿。也就是说,每次释放resourceMutex时,都会有另一个编写者在等待它,因此NO_WRITERS_WRITING永远不会达到零。

要使其按预期运行,请在每个线程的while循环顶部添加一个延迟:

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

这将允许读者在所有作家都在usleep()中时定期获得访问权限。

答案 1 :(得分:0)

  

一开始,所有读者都涌入

通过“进入”,我指的是在printf()循环中执行readerJob调用。读者全都进来并不奇怪,因为您首先启动了它们,并且在第一个尝试锁定tryResourceMutex的读者线程在任何作家线程都这样做之前可能先锁定了{{ 1}}也可以防止任何作者“进来”。 但这不是不会阻止编写者增加resourceMutex()而且也不会阻止其中一个锁定NO_WRITERS_WRITING并将其保持锁定。 / p>

随后,读者中的tryResourceMutex调用将(可能)导致sleep()持续保持足够长的时间,以使所有读者都先于任何一位作家进入,因为每个作家都需要获得{ {1}}进来。

  

然后还有不能同时出现的作家。

我在测试中没有看到。但是,我看到了我已经描述的内容:即使在任何读者都无法进入的情况下,作家人数也从零开始增加。实际上,变量resourceMutex的名称与您的实际用法不一致-表示有多少作者正在写或等待写

当读者离开时,他们被阻止立即重新进入,因为其中一位作家持有resourceMutex。最终,最后一个阅读器将退出并释放NO_WRITERS_WRITING。这将允许编写者一次执行一次操作,但是将tryResourceMutex调用定位在编写者循环中的位置时,编写者的数量极不可能降到零以允许任何写操作继续进行。读者重新进入。但是,如果确实如此,那么很可能会重复相同的循环:所有读者将一次进入,而所有作家都将排队。

  

然后所有的读者都走了,但是图书馆同时有一位以上的作家。

再次,不。一次只有一个作家在里面,而其他大多数时间都在排队,因此resourceMutex几乎总是等于sleep()

那么,底线是:您感到困惑。您正在使用变量NO_WRITERS_WRITING来主要表示准备好写入的作者数,但是您的消息传递将使用该变量,就好像它是实际在写的人数。这不适用于NO_WRITERS,因为一旦线程获取了修改该变量所需的互斥量,其他任何事情都不会阻止它继续进入房间。

还有另一件事:为了使模拟有趣(即,防止编写者获得永久控制权),您应该在每个线程离开房间之后尝试重新进入之前实现一个延迟,最好是一个随机的延迟。而且作家的延迟可能应该比读者的延迟长得多。