【问题标题】:Reader/Writer implementation in CC 中的读取器/写入器实现
【发布时间】:2018-04-14 20:54:08
【问题描述】:

我目前正在我的大学学习并发。在这种情况下,我必须在 C 中实现读写器问题,我认为我走在正确的轨道上。

我对这个问题的想法是,我们需要两个锁rd_lockwr_lock。当写线程想要更​​改我们的全局变量时,它会尝试获取两个锁,写入全局并解锁。当读者想要读取全局时,它会检查wr_lock 当前是否被锁定,然后读取该值,但是其中一个读者线程应该获取rd_lock,但其他读者不应该关心rd_lock 是否被锁定锁定。

不允许我使用 pthread 库中已有的实现。

typedef struct counter_st {
    int value;
} counter_t;

counter_t * counter;
pthread_t * threads;

int readers_tnum;
int writers_tnum;

pthread_mutex_t rd_lock;
pthread_mutex_t wr_lock;

void * reader_thread() {

    while(true) {
        pthread_mutex_lock(&rd_lock);
        pthread_mutex_trylock(&wr_lock);
        int value = counter->value;
        printf("%d\n", value);
        pthread_mutex_unlock(&rd_lock);
    }
}

void * writer_thread() {

    while(true) {
        pthread_mutex_lock(&wr_lock);
        pthread_mutex_lock(&rd_lock);

        // TODO: increment value of counter->value here.
        counter->value += 1;

        pthread_mutex_unlock(&rd_lock);
        pthread_mutex_unlock(&wr_lock);
    }
}

int main(int argc, char **args) {

    readers_tnum = atoi(args[1]);
    writers_tnum = atoi(args[2]);

    pthread_mutex_init(&rd_lock, 0);
    pthread_mutex_init(&wr_lock, 0);

    // Initialize our global variable
    counter = malloc(sizeof(counter_t));
    counter->value = 0;

    pthread_t * threads = malloc((readers_tnum + writers_tnum) * sizeof(pthread_t));
    int started_threads = 0;

    // Spawn reader threads
    for(int i = 0; i < readers_tnum; i++) {
        int code = pthread_create(&threads[started_threads], NULL, reader_thread, NULL);

        if (code != 0) {
            printf("Could not spawn a thread.");
            exit(-1);
        } else {
            started_threads++;
        }
    }

    // Spawn writer threads
    for(int i = 0; i < writers_tnum; i++) {
        int code = pthread_create(&threads[started_threads], NULL, writer_thread, NULL);

        if (code != 0) {
            printf("Could not spawn a thread.");
            exit(-1);
        } else {
            started_threads++;
        }
    }
}

目前,当使用 1 个读取器和 1 个写入器运行时,它只会打印很多零,这意味着它从未真正执行写入器线程中的代码。我知道这不会像预期的那样与多个阅读器一起工作,但是当每个阅读器运行它时,我不明白出了什么问题。

【问题讨论】:

    标签: c pthreads


    【解决方案1】:

    不要将锁视为“读取器锁”和“写入器锁”。

    因为您需要允许多个并发阅读器,所以阅读器不能持有互斥锁。 (如果这样做,它们将被序列化;只有一个可以同时持有一个互斥锁。)他们可以在短时间内(在开始访问之前和结束访问之后)使用一个来更新状态,但这就是它。

    将 rwlock 的时间线分为三个部分:“grab rwlock”“做工作”“释放 rwlock”

    例如,您可以使用一个互斥锁、一个条件变量和一个计数器。计数器保存活动读者的数量。条件变量由最后一个读取器发出信号,写入器在释放互斥体之前发出信号,以唤醒等待的写入器。互斥体保护两者,并在写入操作的整个期间由写入者持有。

    所以,在伪代码中,你可能有

    Function rwlock_rdlock:
        Take mutex
        Increment counter
        Release mutex
    End Function
    
    Function rwlock_rdunlock:
        Take mutex
        Decrement counter
        If counter == 0, Then:
            Signal_on cond
        End If
        Release mutex
    End Function
    
    Function rwlock_wrlock:
        Take mutex
        While counter > 0:
            Wait_on cond
    End Function
    
    Function rwlock_unlock:
         Signal_on cond
         Release mutex
    End Function
    

    请记住,每当您等待条件变量时,互斥锁会在等待期间自动释放,并在线程唤醒时自动获取。因此,对于等待条件变量,线程在等待之前和之后都会有互斥锁,但在等待期间不会。

    现在,上述方法并不是您可以实施的唯一方法。

    特别是,您可能会注意到,在上述方案中,您必须使用不同的“解锁”操作,具体取决于您是在 rwlock 上设置了读锁还是写锁。在 POSIX pthread_rwlock_t 实现中,只有一个 pthread_rwlock_unlock()

    无论你设计什么方案,重要的是检查它是否在所有情况下都能正常工作:一个单独的读锁,一个单独的写锁,几个读锁,几个写锁,一个单独的写- locker 和一个 read-locker,一个单独的 write-locker 和几个 read-locker,几个 write-locker 和一个单独的 read-locker,以及几个读写锁。

    例如,假设有几个活跃的读者,而一个写者想要写锁定 rwlock。

    作者获取互斥锁。然后它注意到计数器非零,因此它开始等待条件变量。当最后一个读者时——注意读者退出的顺序并不重要,因为使用了一个简单的计数器! -- 在 rwlock 上解锁它的读锁,它在条件变量上发出信号,唤醒写入器。然后编写器抓取互斥体,看到计数器为零,然后继续工作。在此期间,互斥锁由写入器持有,因此所有新的读取器都会阻塞,直到写入器释放互斥锁。因为写入器在释放互斥锁时也会在条件变量上发出信号,所以这是其他等待写入器和等待读取器之间的竞争,后者将进入下一个。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-27
      相关资源
      最近更新 更多