rwlock-usage-conclusion

后端开发常常碰到多线程同步问题,也就会经常用到锁,其中关于读写锁,大家还争论不休,主要是很多人会倾向于使用读写锁,认为读写锁能比普通的互斥锁能带来性能的提升,这里先把陈硕大佬总结的贴出来吧(摘自LINUX 多线程服务端编程,第二章,第三节,P23页),大佬说的已经非常全面到位了:

=============================================================================================

=============================================================================================

读写锁(Readers-Writer lock, 简写为rwlock) 是个看上去很美的抽象,它明确区分了read 和 write 两种行为。

初学者常干的一件事情是,一见到某个共享数据结构频繁读而很少写,就把mutex替换为rwlock。甚至首选rwlock来保护共享状态,这不见得是正确的。

从正确性方面来说,一种典型的易犯错误是在持有read lock的时候修改了共享数据。这通常发生在程序的维护阶段,为了增加新功能,程序员不小心在原来read lock保护的函数中调用了会修改状态的函数。这种错误的后果跟无保护并发读写共享数据是一样的。

从性能方面说,读写锁不见得比普通mutex更高效,无论如何reader lock 加锁的开销不会比mutex lock小,因为它需要更新当前reader的数目。如果临界区很小,锁竞争不激烈,那么mutex往往会更快。见$1.9的例子。

reader lock 可能允许提升(upgrade)为writer lock, 也可能不允许提升。考虑$2.1.1的post()和traverse()示例,如果用读写锁保护foos对象,那么post() 应该持有读写锁,而traverse() 应该持有读锁。如果允许吧读锁提升为写锁,后果跟使用recursive mutex一样,会造成迭代器失效,程序崩溃。如果不允许提升, 后果跟使用non-recursive mutex一样,会造成死锁。我宁愿程序死锁,留个“全尸”好查验。

通常reader lock 是可重入的,writer lock是不可重入的。但是为了防止writer饥饿,writer lock 通常会阻塞后来的reader lock,因此reader lock在重入的时候可能死锁。另外,在追求低延迟读取的场合也不适用读写锁。

===========================================================================================

===========================================================================================

这里我也总结下:

1,读写锁一定比互斥锁(普通锁)单次加锁开销大,很容易理解,读写锁要做额外的引用计数已加锁读写性质判别,也做了benchmark,macbook pro i5 8g上,读写锁20ns,普通锁13ns左右

2,读写锁容易误用,例如加了读锁结果进行了写操作

3,读写锁的优势在于可以读并发,那么如果加锁粒度控制的比较小,那么读写锁依然么有优势,如果加锁粒度比较大,那就是设计问题了。。

4,读写锁重入会死锁,比如读锁重入过程中被写锁抢占,就很容易死锁。

5,读写锁的非对称设计会造成延时的抖动,特殊场景不可接受。

6,读写锁的优势场景是  大量的读,读并发,多读少写,https://blog.csdn.net/myz123321/article/details/89048002  像博文中做的实验,上面总结的第一点就解释了,单纯比较rw锁和互斥锁,没有场景的比较没有意义,读写锁必定会慢,读写锁必须用在读并发且大量读少量写的场景,大量读,读并发,多读少写,这三个条件缺一不可,不然就没必要用读写锁,互斥锁就好,具体解释下就是:

a:读并发+大量读,但是没有多读少写,比如读写差不多甚至读比写还少,这个场景显然不需要读写锁,这个是最明显的,因为读写差不多就得互斥锁上了。

b:读并发+多读少写,但是量不大,偶尔才并发一下就没必要,量不大的时候读写锁带来的误用,死锁,性能开销不如用互斥锁,而且这里隐含的场景是读的时间比较集中才会造成读并发但量不大,除了场景原因也有设计问题。

c:大量读+多读少写,即使这种情况,如果大量的读都是分散开的,没有并发读,或者读的量和锁的粒度还没有上升到容易并发读的程度,那么也没必要读写锁,读写锁的优势完全没发挥出来。

 

0

发表评论