多线程:多读少写锁(Readers–writer lock)
先来几个同义词
- readers–writer (RW) lock
- shared - exclusive lock
- multiple readers/single-writer lock
- multi-reader lock
- push lock
解决的问题
- 允许多个线程同时读取数据。只允许一个线程写或更新数据
- 写数据时,其他的写操作和读操作要被阻塞。(SQLite 的 WAL 不是,允许同时读写)
实现时需要考虑的问题
读优先还是写优先?
读优先的概述如下:
尽量满足并发的读操作,当已经有线程在读数据的时候,其他读线程无需等待,而写线程需要等待所有正在进行的读操作之后才能执行
写优先的概述如下:
尽量满足写操作,尽管写操作不能并发,但是可以排队,优先于等待的读线程获得执行权
对系统刷新要求的高标准系统,应该使用写优先的锁,比如路由器、证券交易平台。通常用很多读请求,如果等所有读请求都结束,可能更新信息已经来不及了,即发生 starvation 问题。
解决问题的思路
Readers–writer locks are usually constructed on top of mutexes and condition variables, or on top of semaphores.
- 互斥量+条件变量
- 信号量
具体实现参见参考资料。
默认实现都是读优先的锁。如果要实现写优先的锁,可以通过加标记位判断是否有写请求在等待。
读写锁重入问题及死锁
通常reader lock是可重入的,writer lock是不可重入的。但是为了防止writer饥饿,writer lock通常会阻塞后来的reader lock,因此reader lock在重入的时候可能死锁。
即获取读锁,尝试获取写锁(为了防止饥饿,不允许再次获取读锁),进行重入,即尝试获取读锁。
bingo,发生死锁啦
参考
下起雨,也要勇敢前行