读写锁

读写锁是计算机程序的并发控制的一种同步机制，也称“共享-互斥锁”、多读者-单写者锁。多读者锁"Practical lock-freedom"  by Keir Fraser 2004，“push lock”) 用于解决。读操作可并发重入，写操作是互斥的。这意味着多个线程可以同时读数据，但写数据时需要获得一个独占的锁。当写者写数据时，其它写者或读者需要等待，直到这个写者完成写操作。读写锁常见的用法是控制线程对内存中的某种数据结构的访问，这种数据结构不能被原子性地更新，并且在完成更新之前都是无效的。

读写锁通常用互斥锁、条件变量、信号量实现。

某些读写锁允许在读模式与写模式之间升降级。

优先级策略
读写锁可以有不同的操作模式优先级：

 读操作优先锁：提供了最大并发性，但在锁竞争比较激烈的情况下，可能会导致写操作饥饿。这是由于只要还有一个读线程持锁，写线程就拿不到锁。多个读者可以立刻拿到锁，这意味着一个写者可能一直在等锁，期间新的读者一直可以拿到锁。极端情况下，写者线程可能会一直等锁，直到所有一开始就拿到锁的读者释放锁。读者的可以是弱优先级的，如前文所述，也可以是强优先级的，即只要写者释放锁，任何等待的读者总能先拿到。 
 写操作优先锁：如果队列中有写者在等锁，则阻止任何新读者拿锁，来避免了写操作饥饿的问题。一旦所有已经开始的读操作完成，等待的写操作立即获得锁。和读操作优先锁相比，写操作优先锁的不足在于在写者存在的情况下并发度低。内部实现需要两把互斥锁。 Java readers–writer lock implementation offers a "fair" mode 
 未指定优先级锁：不提供任何读/写的优先级保证。

实现

使用两把互斥锁
使用两把互斥锁与一个整数计数器实现。计数器跟踪被阻塞的读线程。互斥锁保护，供读者使用。互斥锁 (指"global")确保写操作互斥。伪代码：

Begin Read

 Lock .
 Increment .
 If , lock .
 Unlock .

End Read

 Lock .
 Decrement .
 If , unlock .
 Unlock .

Begin Write

 Lock .

End Write

 Unlock .

实现是读操作优先。

使用条件变量与互斥锁
可使用条件变量与普通的互斥锁、整型计数器（表示正在读的个数）与布尔标志（表示正在写）来实现读写锁。

lock-for-read操作：

 Lock  (blocking).
 While :

 Increment .
 Unlock .

lock-for-write操作：

 Lock  (blocking).
 While ( or ):

 Set  to .
 Unlock .

lock-for-read与lock-for-write各自有自己的逆操作。unlock-for-read通过减量并在变为0时通知。unlock-for-write设置为false并通知。

程序语言支持
 POSIX标准的pthread_rwlock_t与相关操作
 ReadWriteLock 接口，ReentrantReadWriteLock锁，从Java版本5开始
 Microsoft System.Threading.ReaderWriterLockSlim锁，用于C♯与.NET语言程序
 std::shared_mutex read/write锁在C++17
 boost::shared_mutex与boost::upgrade_mutex锁在Boost C++ Libraries
 sync.RWMutex在Go语言
 Phase fair reader–writer lock
 std::sync::RwLock，在Rust语言
 Poco::RWLock，在
 mse::recursive_shared_timed_mutex在SaferCPlusPlus库，是支持std::recursive_mutex的recursive ownership语义的std::shared_timed_mutex的一个实现 
 txrwlock.ReadersWriterDeferredLock，用于Twisted
Windows操作系统
SRWLock，见Windows操作系统API，从Windows Vista开始.

读写锁（Slim reader/writer，SRW， lock）用于进程内的线程间同步。 SRW既不是公平的也不是先进先出的。读写锁数据结构的内部实现就是一个指针。读写锁的性能较临界区有很大的提升，这是因为读写锁是基于原子操作，关键段是基于event内核对象的，从用户模式到内核模式的切换占用了大量的时钟周期。相关API：
InitializeSRWLock：动态初始化SRW结构。也可以直接赋值SRWLOCK_INIT常量来静态初始化SRW结构。不需要显式析构。
AcquireSRWLockShared：获取共享读的SRW锁。
AcquireSRWLockExclusive：获取专享写的SRW锁。
TryAcquireSRWLockShared：试图获取共享读的SRW锁。
TryAcquireSRWLockExclusive：试图获取专享写的SRW锁。
ReleaseSRWLockShared：释放已经获取的共享读的SRW锁。
ReleaseSRWLockExclusive：释放已经获取的专享写的SRW锁。
SleepConditionVariableSRW：在已经获取SRW锁的前提下，原子操作：在指定条件变量上睡眠并释放SRW锁

可选
read-copy-update (RCU)算法是读写锁的一种替代实现。RCU对读操作是无等待。Linux内核实现了很少写操作的一种RCU叫做seqlock。

参见
 信号量
 互斥锁
 调度 (计算机)

 文件锁定
 锁 (计算机科学)

注释

参考文献


Category:并发控制