> For the complete documentation index, see [llms.txt](https://lester123.gitbook.io/rust-simple/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lester123.gitbook.io/rust-simple/untitled-1.md).

# Rust中的读写锁RwLock

本文简单介绍 Rust 中的读写锁`RwLock`，内容概览如下：

* 经典问题
  * 读者-作家问题
* 基本概念
  * 临界区 Critical section
  * 互斥量 Mutex
  * 信号量 Semaphore
  * 读写锁 RWLock
* RwLock实现
  * std::sync::RwLock
  * parking\_lot::RwLock

## 经典问题

在计算机科学中，有一些经典的同步问题，读者-作家问题就是其中一个，该问题涉及多个并发线程试图同时访问同一共享资源的情况。

**读者-作家问题**：我们拥有一种资源（例如，数据库），可以由不修改资源的读者和可以修改资源的作家访问。当作家修改资源时，其他任何人（读者或作家）都无法同时访问它，因为另一位作家可能破坏资源，而另一位读者可能读取部分修改的值，因此可能出现不一致。

## 基本概念

为了准确理解问题，我们先介绍一些基本概念。

**临界区 Critical section**，在并发编程中，对共享资源的并发访问可能导致意外或错误的行为，因此需要以某种方式保护访问共享资源的那部分程序。这部分受保护的代码片段称为临界区。

**互斥量 Mutex**，在多线程并发编程时，为了确保一次仅一个线程可以访问共享资源，引入了`Mutex`的概念，它是 Mutual Exclusion 的缩写，通常翻译为互斥量或互斥锁。

**信号量 Semaphore**，同样的，为了控制并发系统中多个线程对共享资源的访问，引入了`Semaphore`的概念，通常翻译为信号量。

**读写锁 RWLock**，在计算机科学中，读写锁是解决读者-作家问题的同步原语之一。读写锁允许读操作共享访问，而写操作则需要互斥访问。通常构造在互斥量和条件变量之上，或者构造在信号量之上。

## Rust中的读写锁

自读者-作家问题提出以来，人们对它进行了广泛的研究，读写锁是解决读者-作家问题的方案之一，按照锁定的锁定的优先级策略分为以下三种：

* **赋予读者优先权**：当前至少有一个读者正在访问资源时，也应允许新读者访问它。如果有作家在等待修改资源并且新的读者一直到来，这可能会导致作家饿死，因为只要有至少一个读者，就永远不会授予作家访问权限。
* **赋予作家优先权**：在这里，读者可能会饿死。
* **不给予任何优先权**：所有读者和作家都将按到达顺序被授予对资源的访问权限。如果在读者访问资源时作家到达，它将等待这些读者释放资源，然后对其进行修改。同时抵达的新读者将不得不等待。

标准库中的RwLock：

* 允许在任何时间点具有多个读者或最多一个作家。也就是说，RwLock允许任何数量的读者获取锁，只要作家未持有该锁即可。
* 相比之下，互斥锁不会区分获取锁的种类，因此会阻塞等待可用锁的所有线程。
* 锁定的优先级策略取决于操作系统的实现，也就是说它不能保证将使用任何特定的优先级策略。
  * Windows和macOS，读者和作家公平排队
  * Linux，读者优先，作家会饿死

```rust
use std::sync::RwLock;

let lock = RwLock::new(5);

// many reader locks can be held at once
{
    let r1 = lock.read().unwrap();
    let r2 = lock.read().unwrap();
    assert_eq!(*r1, 5);
    assert_eq!(*r2, 5);
} // read locks are dropped at this point

// only one write lock may be held, however
{
    let mut w = lock.write().unwrap();
    *w += 1;
    assert_eq!(*w, 6);
} // write lock is dropped here
```

与标准库RwLock的区别：

* 支持以原子方式将写锁降级为读锁。
* 公平任务锁定策略，而不是未指定的平台默认值。
* 没有中毒，该锁通常在出现紧急情况时被释放。
* 仅需要1个字的空间，而标准库由于平台限制而将RwLock装箱。
* 可以静态构造（需要const\_fn nightly功能）。

  掉落时不需要任何滴胶。

  内联快速路径，适用于无竞争的情况。

  使用自适应旋转有效处理微争用。

  无需保护即可进行原始锁定和解锁。

  支持最终的公平性，因此rwlock平均而言是公平的。

  （可选）通过调用RwLockReadGuard :: unlock\_fair和RwLockWriteGuard :: unlock\_fair来使rwlock公平。
