目录
一、读写锁
二、读写锁接口
【2.1】设置读写优先
【2.2】初始化
【2.3】销毁
【2.4】加读锁
【2.5】加写锁
【2.6】解锁
三、读写锁实例
一、读写锁
在编写多线程的时候,有一种情况是十分常见的。那就是,有些公共数据修改的机会比较少。相比较改写,它们读的机会反而高的多。通常而言,在读的过程中,往往伴随着查找的操作,中间耗时很长。给这种代码段加锁,会极大地降低我们程序的效率。那么有没有一种方法,可以专门处理这种多读少写的情况呢? 有,那就是读写锁。
这里默认是读锁优先的,因为读者非常的多,但是这样也就会导致写锁的饥饿问题。
读者写者模型和生产者消费者模型的区别? 读者写者模型和生产者消费者模型最大的区别就是生产者生产数据之后,消费者就会将数据消费掉,其他消费者则无法享受该数据。而读者写者模型中写者进行数据的写入时,所有的读者都可以享受该数据,直到写者再次写入。
读者写者模型中的三重关系?
-
写者和写者的关系:互斥。
-
读者和读者的关系:共享。
-
读者和写者的关系:互斥和同步(当写者进行数据写入时,读者不可以进行数据的读取,当读者进行数据的读取时,写者不可以进行数据的写入,同时读者必须等待写者把数据写完才可以进行数据的写入)。
既然读读不互斥,为何还要加读锁?
-
如果只是读,是不需要加锁的,加锁本身就有性能上的损耗。
-
如果读可以不是最新数据,也不需要加锁。
-
如果读必须是最新数据,必须加读写锁。
-
读写锁相较于互斥锁的优点仅仅是允许读读的并发,除此之外并无其他。
二、读写锁接口
【2.1】设置读写优先
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 写者优先,但写者不能递归加锁
*/
【2.2】初始化
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
// 功能: 初始化读写锁
// 参数说明:
// rwlock: 是要进行初始化的读写锁
// attr:是rwlock的属性,此参数一般不关注,可设为NULL
【2.3】销毁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
// 功能: 销毁初始化的锁
// 参数说明:
// rwlock: 是需要进行销毁的锁
【2.4】加读锁
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
【2.5】加写锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
【2.6】解锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
三、读写锁实例
#include <iostream>
#include <pthread.h>
#include <unistd.h>
int data = 0; // 全局读写临界资源
pthread_rwlock_t rwlock; // 全局读写锁
/* - 读者线程
*/
void *Reader(void *arg)
{
while (true)
{
// 加读锁
pthread_rwlock_rdlock(&rwlock);
std::cout << "reader down:" << data << std::endl;
// 解锁
pthread_rwlock_unlock(&rwlock);
sleep(2);
}
}
/* - 写者线程
*/
void *Writer(void *arg)
{
while (true)
{
// 加写锁
pthread_rwlock_wrlock(&rwlock);
std::cout << "writer down:" << ++data << std::endl;
// 解锁
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
}
/* - 程序入口函数
*/
int main()
{
// 初始化读写这锁
pthread_rwlock_init(&rwlock, NULL);
// 创建读者线程
pthread_t r[5];
pthread_create(&r[0], nullptr, Reader, nullptr);
pthread_create(&r[1], nullptr, Reader, nullptr);
pthread_create(&r[2], nullptr, Reader, nullptr);
pthread_create(&r[3], nullptr, Reader, nullptr);
pthread_create(&r[4], nullptr, Reader, nullptr);
// 创建读者线程
pthread_t w;
pthread_create(&w, nullptr, Writer, nullptr);
// 线程等待
for (int i = 0; i < 5; i++)
{
pthread_join(r[i], nullptr);
}
pthread_join(w, nullptr);
// 释放读写这锁
pthread_rwlock_destroy(&rwlock);
return 0;
}
// 打印结果:
reader down:0
writer down:1
writer down:2
reader down:2
reader down:2
reader down:2
reader down:2
reader down:2
writer down:3
writer down:4
reader down:4
reader down:4
reader down:4
reader down:4
reader down:4
writer down:5
writer down:6
reader down:6
reader down:6
reader down:6
reader down:6
reader down:6