操作系统 c 读者写者问题

操作系统 c 读者写者问题

问题描述:

如果你建立了一个数据库,同时可以通过多个线程被多个远程用户使用,其中一些用户只需要查看数据,而另一些用户需要修改数据。

显然:

  1. 你不能允许两个用户同时修改数据,
  2. 但你也不能允许一个用户在修改数据时、另一个用户来读取数据,因为这时后一个用户读取到的数据可能是没有被完全更新的数据。

​ 因此我们需要一个特殊的管程,在没有写入数据的线程时,它允许多个线程同时读取数据;在有线程读取数据时,想要写入数据的线程就需要等待;在有线程写入数据时,所有其它线程均需要等待;在同时有读者和写者等待时,优先运行写者线程,使得读者获取最新数据。

代码封装

我们可以定义一个新的锁,叫做rdwr_lock,每个用户进入这个系统时都需要先获得这个锁,然后才能执行读写操作。虽然我们叫它“锁”,但严格意义上来讲,它并不是完全互斥的,多个读者可以同时获得锁,我们需要实现的是写者之间的互斥和写者与读者之间的互斥,因此我们需要两个变量:读者数量与写者数量,以支持两种不同的获得锁的模式。同时,我们需要一个锁来保护rdwr_lock的内部数据。那么我们可以初步定义struct rdwr_lock如下:

struct rdwr_lock{
    pthread_mutex_t mutex;
    int reader_number;
    int writer_number;
};

按照我们之前提到的条件,当写者数量大于0时,读者和写者都需要等待,而当读者数量大于0时,写者也需要等待,因此我们需要两个条件变量来实现针对这两个条件的等待。因此我们需要更新struct rdwr_lock如下:

struct rdwr_lock{
    pthread_mutex_t mutex;
    pthread_cond_t can_read;
    pthread_cond_t can_write;
    int reader_number;
    int writer_number;
    int waiting_readers;
    int waiting_writers;
};

由于读者与写者获取锁的条件不同,我们现在定义如下的四个函数,分别给读者、写者用来获取、释放锁:

void acquire_read_lock(struct rdwr_lock *lock);
void unlock_read_lock(struct rdwr_lock *lock);
void acquire_write_lock(struct rdwr_lock *lock);
void unlock_write_lock(struct rdwr_lock *lock);

现在我们先来实现第一个函数void acquire_read_lock(struct rdwr_lock *lock);。像我们前面提到的那样,在有线程正在写入数据或有写者线程正在等待时,我们就需要等待,因此函数实现如下:

void acquire_read_lock(struct rdwr_lock *lock){
    pthread_mutex_lock(&lock->mutex);
    while (lock->writer_number + lock->waiting_writers > 0) {
        lock->waiting_readers += 1;
        pthread_cond_wait(&lock->can_read, lock);
        lock->waiting_readers -= 1;
    }
    lock->reader_number += 1;
    pthread_mutex_unlock(&lock->mutex);
}

鉴于读者的存在不会导致其它读者被阻塞,在一个读者离开系统时,它只需要查看系统内是否有等待的写者。因此我们可以实现void unlock_read_lock(struct rdwr_lock *lock);如下:

void unlock_read_lock(struct rdwr_lock *lock){
    pthread_mutex_lock(&lock->mutex);
    lock->reader_number -= 1;
    if (lock->waiting_writers>0) {
        pthread_cond_signal(&lock->can_write);
    }
    pthread_mutex_unlock(&lock->mutex);
}

类似的,我们可以实现写者进入和离开系统的函数:

void acquire_write_lock(struct rdwr_lock *lock){
    pthread_mutex_lock(&lock->mutex);
    while (lock->writer_number + lock->reader_number > 0) {
        lock->waiting_writers += 1;
        pthread_cond_wait(&lock->can_write, lock);
        lock->waiting_writers -= 1;
    }
    lock->writer_number += 1;
    pthread_mutex_unlock(&lock->mutex);
}

void unlock_write_lock(struct rdwr_lock *lock){
    pthread_mutex_lock(&lock->mutex);
    lock->write_number -= 1;
    if (lock->waiting_writers>0) {
        pthread_cond_signal(&lock->can_write);
    } else if (lock->waiting_readers>0) {
        pthread_cond_broadcast(&lock->can_read);
    }
    pthread_mutex_unlock(&lock->mutex);
}

需要注意的是,一个写者既能阻塞写者,也能阻塞读者,所以它在离开系统时必须检查系统中是否存在等待的写者和读者。如果有等待的写者,则它优先唤醒写者,否则它唤醒 所有等待的读者

以上来自计蒜客。。 大致上原理是可以理解的

读写锁介绍

     读写锁的类型是pthread_rwlock_t,如果这个类型的某个变量是静态分配的,那么可以通过PTHREAD_RWLOCK_INITIALIZER来初始化它。

扫描二维码关注公众号,回复: 5623033 查看本文章

            pthread_rwlock_rdlock获取一个读出锁,如果对应的读写锁已由某个写入者持有,那就阻塞调用线程。pthread_rwlock_wrlock获取一个写入锁,如果对应的读写锁已由另一个写入者持有,或者已由一个或多个读出者持有,那就阻塞调用线程。pthread_rwlock_unlock释放一个读出锁或写入锁。

	pthread_rwlock_rdlock(pthread_rwlock_t *rwpt);
	pthread_rwlock_wrlock(pthread_rwlock_t *rwpt);
	pthread_rwlock_unlock(pthread_rwlock_t *rwpt);    

猜你喜欢

转载自blog.csdn.net/weixin_39722329/article/details/87969324