读者写者模式
读写锁
在编写多线程的时候,有一种情况是十分常见的。那就是,有些公共数据修改的机会比较少。相比较改写,它们读的机会反而高的多。通常而言,在读的过程中,往往伴随着查找的操作,中间耗时很长。给这种代码段加锁,会极大地降低我们程序的效率。那么有没有一种方法,可以专门处理这种多读少写的情况呢? 有,那就是读写锁。
读者和读者之间无互斥关系,可并行访问;
读者和写者之间是互斥关系,一方操作时另一方必须等待;
写者和写者之间也是互斥关系。
读写锁原理细节:
第一个到达的读者需要加锁,阻止写者进入; 后续新来的读者直接进入读取,计数累加; 最后一个读完的读者释放锁,写者才有机会写入。
读写锁接口
设置读写优先
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 写者优先,但写者不能递归加锁 */初始化
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);销毁:
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);读者优先:
只要有读者正在读,后续新来的读者全都可以插队进入读取;写者会一直被阻塞,极易写者饥饿(写者迟迟得不到执行机会)。
共用基础变量:read_count:正在读的读者数量,初值 = 0mutex:保护 read_count 的互斥锁wrt:读写共用锁(写者占用后,任何人都进不来)
一、读者优先
核心思想
只要有读者正在读,后续新来的读者全都可以插队进入读取;写者会一直被阻塞,极易写者饥饿(写者迟迟得不到执行机会)。
共用基础变量:read_count:正在读的读者数量,初值 = 0
mutex:保护 read_count 的互斥锁
wrt:读写共用锁(写者占用后,任何人都进不来)
执行逻辑
- 读者到来:
- 先抢占 mutex 锁,修改 read_count
- 若自己是第一个读者:抢占 wrt 锁(锁住资源,不让写者进来)
- read_count++,释放 mutex,开始读文件
- 读者离开:
- 抢占 mutex,read_count--
- 若自己是最后一个读者:释放 wrt 锁,写者才有资格竞争资源
- 释放 mutex
- 写者到来: 直接申请 wrt 锁,拿不到就阻塞; 只要还有读者在读,wrt 永远不会释放,写者持续等待。
优缺点
✅ 读者效率极高,并发读取顺畅 ❌ 致命缺陷:写者饥饿
二:写者优先:
核心思想
一旦有写者等待资源,后续所有新来的读者全部阻塞排队;必须等所有等待 + 正在执行的写者全部完成后,读者才能继续读。 杜绝写者饥饿,但会出现读者饥饿。
新增变量:write_wait:等待中的写者数目read_queue:读者等待队列
执行逻辑
- 只要存在等待的写者:拒绝所有新读者入场
- 写者到达优先级 > 新来读者
- 所有排队写者依次写完,资源空闲后,才放行积压的读者
优缺点
✅ 写者不会饿死,写入响应快 ❌ 大量读者堆积等待,读者饥饿
三、公平读写(队列先来先服务 FIFO,无饥饿)
核心思想
按照进程到达的先后顺序排队,严格遵循先来后到:
- 排在队列首位的进程获得资源使用权
- 若队首是读者:连续放行队列里紧随其后的所有读者一起读
- 若队首是写者:只允许这一个写者独占资源,写完才轮到下一批进程
效果
读者、写者地位均等,既不会读者饥饿,也不会写者饥饿,整体吞吐最均衡。