【Linux】读写者模型-读写锁

在编写多线程的时候,有⼀种情况是⼗分常⻅的。那就是,有些公共数据修改的机会⽐较少。相⽐较改写,它们读的机会反⽽⾼的多。通常⽽⾔,在读的过程中,往往伴随着查找的操作,中间耗时很⻓。给这种代码段加锁,会极⼤地降低我们程序的效率。那么有没有⼀种⽅法,可以专⻔处理这种多读少写的情况呢? 有,那就是读写锁。读写锁本质上是⼀种⾃旋锁。

写互斥,读共享。写的时候别人不能写也不能读,但是大家可以一起读取。加写锁的时候判断write是否大于0;如果大于零代表有人加写锁,将阻塞,否则write计数器+1;加写锁的时候判断read是否大于0;如果大于零代表有人加读锁,将阻塞,否则write计数器+1;加读锁的时候判断write是否大于0;如果大于零代表有人加写锁,将阻塞,否则read计数器+1;

读写锁,默认加读锁优先,但这种情况会造成饥饿情况。因此使用的时候需要重新设置读写锁为加写锁优先(等待两个计数都为0;并且拒绝在这期间其他加读锁的操作)。

读写锁是使用自旋锁实现的,条件不满足一直循环判断,耗费CPU资源较多。自旋锁是不断发起加锁请求。

使用场景:

1.写的操作少,读的操作多。

2.不管读操作还是写操作,操作时间都比较短。

设置读写优先

//初始化读写锁属性
pthread_rwlockattr_init(pthread_rwlockattr_t* attr);


//设置写锁优先
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t* attr, int pref);
pref 共有3种选择

PTHREAD_RWLOCK_PREFER_READER_NP (默认设置)住着优先,可能会导致写着饥饿情况

PTHREAD_RWLOCK_PREFER_WRITER_NP   写着优先,目前有bug,导致表现行为和PTHREAD_RWLOCK_PREFER_READER_NP一致

PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP    写着优先,但写着不能递归枷锁


//释放读写锁属性
pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);

初始化

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
rwlock:读写锁变量
attr:   读写锁属性
返回值:失败:错误编号   成功: 0

销毁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

加读锁

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 <iostream>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
using namespace std;

pthread_rwlock_t rwlock;
void* reader(void* arg)
{
    cout << "start read" << endl;
    while(1)
    {
        pthread_rwlock_rdlock(&rwlock);
        cout << "read lock!!" <<pthread_self() << endl;
        sleep(1);
        pthread_rwlock_unlock(&rwlock);
    }
    return NULL;
}

void* writer(void* arg)
{
    while(1)
    {
        pthread_rwlock_wrlock(&rwlock);
        cout << "------write lock!!" << endl;
        sleep(3);
        pthread_rwlock_unlock(&rwlock);
        cout << "------write over" << endl;
    }
    return NULL;
}

int main()
{
    pthread_t rtid[4], wtid;
    int i;
    pthread_rwlock_init(&rwlock, NULL);
    for(i = 0; i < 4; ++i)
    {
        pthread_create(&rtid[i], NULL, reader, NULL);
    }

    pthread_create(&wtid, NULL, writer, NULL);

    pthread_join(wtid, NULL);

    for(i = 0; i < 4; ++i)
    {
        pthread_join(rtid[1], NULL);
    }


    pthread_rwlock_destroy(&rwlock);
    return 0;
}

很明显,四个读锁优先加锁,导致写锁一直得不到时间片,所以加不上。

设置&测试写锁优先

#include <iostream>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
using namespace std;

pthread_rwlock_t rwlock;
void* reader(void* arg)
{
    cout << "start read" << endl;
    while(1)
    {
        pthread_rwlock_rdlock(&rwlock);
        cout << "read lock!!" <<pthread_self() << endl;
        sleep(1);
        pthread_rwlock_unlock(&rwlock);
    }
    return NULL;
}

void* writer(void* arg)
{
    while(1)
    {
        pthread_rwlock_wrlock(&rwlock);
        cout << "------write lock!!" << endl;
        sleep(3);
        pthread_rwlock_unlock(&rwlock);
        cout << "------write over" << endl;
    }
    return NULL;
}

int main()
{
    pthread_t rtid[4], wtid;

    //设置写锁优先
    pthread_rwlockattr_t attr;
    //初始化读写锁属性
    pthread_rwlockattr_init(&attr);
    //设置写锁优先
    pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
    int i;
    pthread_rwlock_init(&rwlock, &attr);
    //释放读写锁属性
    pthread_rwlockattr_destroy(&attr);
    for(i = 0; i < 4; ++i)
    {
        pthread_create(&rtid[i], NULL, reader, NULL);
    }

    pthread_create(&wtid, NULL, writer, NULL);

    pthread_join(wtid, NULL);

    for(i = 0; i < 4; ++i)
    {
        pthread_join(rtid[1], NULL);
    }


    pthread_rwlock_destroy(&rwlock);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yulong__li/article/details/85266996