了解了互斥锁,就来到了第二种问题:读写锁
一、读者-写者问题
当多线程访问同一个共享数据,会对数据进行读或写操作,当读进程很多的时候,一个一个用互斥锁未免开销太大,一般“读”这种不改变共享数据的操作之间,不互斥也不会有什么大偏差,而写操作这种会改变数据的操作,互斥是必须的。故封装好的读写锁函数应该满足以下条件:
1)读与读进程之间可以同时访问共享数据
2)任一写者完成写操作前,不允许其他读写者工作
二、读写锁
定义读写锁:pthread_rwlock_t rwlock;
五个函数:
1)int pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock) 初始化读写锁
2)int pthread_rwlock_destroy(pthread_rwlock_t *__rwlock) 销毁锁
3)int pthread_rwlock_rdlock(pthread_rwlock_t *__rwlock) 获取读锁
4)int pthread_rwlock_unlock(pthread_rwlock_t *__rwlock) 解锁(读/写线程都可)
5)int pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock) 获取写锁



三、读写锁的写饥饿机制
以上开启了三个读线程,一个写线程,并且写线程先被创建,然而运行结果却是:

写线程等三个读线程把自己三轮读取全部跑完,不再申请读锁了,写线程才终于抢到第二次写锁,改成30。
这是因为:Linux 默认 pthread_rwlock_t 是读优先:
- 只要有读锁被持有,后续新来的读请求可以直接拿到锁
- 写请求必须等当前所有读全部释放,并且没有新读进来,才能拿到写锁
怎么解决呢?
其实只需要在初始化读写锁的时候加上PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP属性

然而本人又踩了个坑,在我加上写优先属性再去初始化,却忘了删掉之前不带属性的最初版本的初始化,导致重复初始化,覆盖了前面写好的写优先属性,,,,,,
好了,加了写优先属性后的结果显而易见:写线程较之前提前抢到了锁,太不容易了。

本文深入解析Linux系统编程中pthread_rwlock_t读写锁的机制,涵盖读者-写者问题建模、五个核心API(初始化、销毁、读锁、写锁、解锁)、读优先导致的写饥饿现象,以及通过PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP属性实现写优先的实践方法。重点强调属性设置时机与避免重复初始化的关键细节。
224

被折叠的 条评论
为什么被折叠?



