读者写者问题

1.相关概念

    在编写多线程的时候, 有一种情况十分常见. 那就是有些公共数据修改的机会特别少, 相比较改写, 数据被读的概率较高. 通常而言, 读的时候会常常伴随着查找的过程, 这就相对的比较耗时, 如果在读的过程中给其加锁, 那么写端可能会引起饥饿现象, 为了防止写端饥饿产生, 因此通常情况下规定写者优先权高于读者优先权.
    例如一个飞机订票系统, 其中许多竞争的进程视图读写其中相关的数据, 当多个线程同时读数据时, 操作系统是允许的, 但当多个同时对数据进行写的时候, 就会出现数据不一致的情况, 为了解决上述问题, 规定, 当有一个线程在对数据进行写的时候, 其他线程都不能访问该数据, 就算是读者也不可以.在这里必须注意, 当只有一个读者进入飞机订票系统的数据库的时候, 另一个读者又进来了, 同时允许多个读者访问该数据库.但是, 此时写者过来了, 由于写者的行为是排他的, 不能允许写着进入飞机订票系统数据库, 所以此时的写者只能被挂起, 如果规定, 只要有一个读者在,那么后继的读者都允许进入该数据库对其进行访问. 这样, 如果不断的有读者到来, 那么写着将会一直被挂起, 长时间会引起写者的饥饿现象. 所以为了避免这种情况的出现, 规定, 当在一个读者到达, 且一个写者在等待时,当再有读者到来时, 新的读者将会在写者之后被挂起, 而不是直接进入. 这样当有读者在读时, 一个写者到来时, 写者只需等待正在读的这个进程读完就可进入, 而不需要一直等到所有读者读完才进入.

2. 读者写着问题和生产者消费者的比较

    (1)读者写者问题之间的相互关系是一下这种:
      1)读者和读者之间是共享关系
     2)读者和写者之间是同步互斥关系
     3)写者和写者之间是互斥关系
    (2)生产者和消费者之间的关系是一下三种关系
     1)生产者和生产者之间是互斥关系
     2)生产者和消费者之间是同步互斥关系
     3)消费者和消费者之间是互斥关系
     之所以会有上面的不同, 只要是因为消费者在消费的过程中会将数据带走, 而读者不会将数据带走, 因此读者和读者之间的关系是共享关系

3. 相关读写锁接口
1. 读写锁的初始化
int pthread_rwlock_init(pthread_rwlock_t* restr rwlock, const pthread_rwlockattr_t* restrict attr);
2.读写所得销毁
int pthread_rwlock_destroy(pthread_rwlock* rwlock);
3. 加锁解锁
int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);

int pthread_rwlock_unlock(pthread_rwlock_t* rwlock);

    有了上面介绍的读写锁相关接口, 就可以通过代码实现读写锁相关案例了

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<unistd.h>

int count;
pthread_rwlock_t rw_lock;

void* route_write(void* arg)
{
    int t = 0;
    int num = *(int*)arg;
    free(arg);
    while(1)
    {
        sleep(1);
        t = count;
        pthread_rwlock_wrlock(&rw_lock);
        printf("write:%d:%#X:count = %d ++count = %d\n", num, pthread_self(), t, ++count);
        pthread_rwlock_unlock(&rw_lock);
        sleep(1);
    }
}

void* route_read(void* arg)
{
    int t = 0;
    int num = *(int*)arg;
    while(1)
    {
        t = count;
        pthread_rwlock_wrlock(&rw_lock);
        printf("read:%d:%#X:count = %d\n", num, pthread_self(), count);
        pthread_rwlock_unlock(&rw_lock);
        sleep(3);
    }
}
int main()
{
    int i = 0;
    pthread_t tid[8];

    pthread_rwlock_init(&rw_lock, NULL);
    for(; i < 3; i++)
    {
        int* p = (int*)malloc(sizeof(int));
        pthread_create(tid + i, NULL, route_write, (void*)p);
    }

    for(i = 0; i < 5; i++)
    {
        int* p = (int*)malloc(sizeof(int));
        pthread_create(tid + i, NULL, route_read, (void*)p);
    }

    for(i = 0; i < sizeof(tid) / sizeof(tid[0]); i++)
    {
        pthread_join(tid[i], NULL);
    }

    pthread_rwlock_destroy(&rw_lock);
    return 0;
}

                           这里写图片描述
    可以看出, 加了读写锁之后, 读者每次拿到的是最新的数据, 不会出现数据不一致的情况

猜你喜欢

转载自blog.csdn.net/qq_41027326/article/details/80038139