> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/man/man9/rmlock.9.md).

# rmlock.9

`rmlock` — 内核读/写锁，针对以读为主的访问模式进行了优化

## 名称

`rmlock`, `rm_init`, `rm_init_flags`, `rm_destroy`, `rm_rlock`, `rm_try_rlock`, `rm_wlock`, `rm_runlock`, `rm_wunlock`, `rm_wowned`, `rm_sleep`, `rm_assert`, `RM_SYSINIT`, `RM_SYSINIT_FLAGS`, `rms_init`, `rms_destroy`, `rms_rlock`, `rms_wlock`, `rms_runlock`, `rms_wunlock`

## 概要

```c
#include <sys/param.h>
```

```c
#include <sys/lock.h>
```

```c
#include <sys/rmlock.h>
```

```c
void
rm_init(struct rmlock *rm, const char *name)

void
rm_init_flags(struct rmlock *rm, const char *name, int opts)

void
rm_destroy(struct rmlock *rm)

void
rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker)

int
rm_try_rlock(struct rmlock *rm, struct rm_priotracker *tracker)

void
rm_wlock(struct rmlock *rm)

void
rm_runlock(struct rmlock *rm, struct rm_priotracker *tracker)

void
rm_wunlock(struct rmlock *rm)

int
rm_wowned(const struct rmlock *rm)

int
rm_sleep(void *wchan, struct rmlock *rm, int priority, const char *wmesg, int timo)
```

```c
options INVARIANTS
options INVARIANT_SUPPORT

void
rm_assert(struct rmlock *rm, int what)
```

```c
#include <sys/kernel.h>
```

```c
RM_SYSINIT(name, struct rmlock *rm, const char *desc)
RM_SYSINIT_FLAGS(name, struct rmlock *rm, const char *desc, int flags)

void
rms_init(struct rmslock *rms, const char *name)

void
rms_destroy(struct rmslock *rms)

void
rms_rlock(struct rmslock *rms)

void
rms_wlock(struct rmslock *rms)

void
rms_runlock(struct rmslock *rms)

void
rms_wunlock(struct rmslock *rms)
```

## 描述

读优先锁（read-mostly lock）允许多个线程共享访问受保护的数据，或单个线程独占访问。具有共享访问权限的线程被称为*读者*，因为它们只读取受保护的数据。具有独占访问权限的线程被称为*写者*，因为它可以修改受保护的数据。

读优先锁的设计目标是高效处理几乎只用作读者锁的锁，因此应用于保护很少变更的数据。在锁已被共享锁定后获取独占锁是一项开销很大的操作。

普通的读优先锁类似于 [rwlock(9)](/man/man9/rwlock.9.md) 锁，并遵循与 [rwlock(9)](/man/man9/rwlock.9.md) 锁相同的加锁顺序规则。读优先锁具有与互斥锁类似的完整优先级传播。与 [rwlock(9)](/man/man9/rwlock.9.md) 不同的是，读优先锁会向读者和写者都传播优先级。这是通过传递给 `rm_rlock` 和 `rm_runlock` 的 `rm_priotracker` 结构参数实现的。如果锁以 `RM_RECURSE` 选项初始化，读者可以递归加锁；但写者永远不允许递归。

通过向 `rm_init_flags` 传递 `RM_SLEEPABLE` 标志，可以允许写者睡眠。这会将加锁顺序规则更改为与 [sx(9)](/man/man9/sx.9.md) 锁相同。此类锁不会向写者传播优先级，但会向读者传播优先级。注意，无论该标志如何设置，读者都不允许睡眠。

可睡眠的读优先锁（通过 `rms_init` 创建）允许读者和写者都睡眠，但不会向任何一方传播优先级。它们遵循 [sx(9)](/man/man9/sx.9.md) 的加锁顺序。

### 宏和函数

**`RM_NOWITNESS`** 指示 [witness(4)](/man/man4/witness.4.md) 忽略此锁。

**`RM_RECURSE`** 允许线程递归获取 `rm` 的共享锁。

**`RM_SLEEPABLE`** 创建可睡眠的读优先锁。

**`RM_NEW`** 如果内核编译时启用了 `option INVARIANTS`，`rm_init_flags` 会断言 `rm` 未在前一次调用 `rm_destroy` 之前被多次初始化，除非指定了此选项。

**`RM_DUPOK`** [witness(4)](/man/man4/witness.4.md) 不应记录获取重复锁的消息。

**`RA_LOCKED`** 断言当前线程持有 `rm` 的共享锁或独占锁。

**`RA_RLOCKED`** 断言当前线程持有 `rm` 的共享锁。

**`RA_WLOCKED`** 断言当前线程持有 `rm` 的独占锁。

**`RA_UNLOCKED`** 断言当前线程既不持有 `rm` 的共享锁，也不持有独占锁。

**`RA_RECURSED`** 断言当前线程持有 `rm` 的递归锁。

**`RA_NOTRECURSED`** 断言当前线程不持有 `rm` 的递归锁。

**`rm_init(struct rmlock *rm, const char *name)`** 初始化读优先锁 `rm`。`name` 描述仅用于调试目的。在对此锁执行任何其他操作之前，必须调用此函数。

**`rm_init_flags(struct rmlock *rm, const char *name, int opts)`** 类似于 `rm_init`，使用一组可选标志初始化读优先锁 `rm`。`opts` 参数包含以下一个或多个标志：

**`rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker)`** 以读者身份锁定 `rm`，使用 `tracker` 跟踪锁的读者所有者以进行优先级传播。此数据结构仅由 `rms_wunlock` 内部使用，必须持续存在直到调用 `rm_runlock`。由于读者不能睡眠，此数据结构可以在栈上分配。如果有线程独占持有此锁，当前线程将阻塞，其优先级会传播给独占持有者。如果锁以 `RM_RECURSE` 选项初始化，则当当前线程已获取 `rm` 的读者访问权限时，仍可调用 `rm_rlock`。

**`rm_try_rlock(struct rmlock *rm, struct rm_priotracker *tracker)`** 尝试以读者身份锁定 `rm`。如果无法立即获取锁，`rm_try_rlock` 将返回 0；否则将获取锁并返回非零值。注意，即使锁当前未被写者持有，`rm_try_rlock` 也可能失败。如果锁以 `RM_RECURSE` 选项初始化，当当前线程已获取读者访问权限时，`rm_try_rlock` 将成功。

**`rm_wlock(struct rmlock *rm)`** 以写者身份锁定 `rm`。如果有任何共享持有者，当前线程将阻塞。`rm_wlock` 不能递归调用。

**`rm_runlock(struct rmlock *rm, struct rm_priotracker *tracker)`** 此函数释放先前由 `rm_rlock` 获取的共享锁。`tracker` 参数必须与获取共享锁时使用的 `tracker` 参数匹配。

**`rm_wunlock(struct rmlock *rm)`** 此函数释放先前由 `rm_wlock` 获取的独占锁。

**`rm_destroy(struct rmlock *rm)`** 此函数销毁先前由 `rm_init` 初始化的锁。`rm` 锁必须处于未锁定状态。

**`rm_wowned(const struct rmlock *rm)`** 如果当前线程拥有 `rm` 的独占锁，此函数返回非零值。

**`rm_sleep(void *wchan, struct rmlock *rm, int priority, const char *wmesg, int timo)`** 此函数在等待事件时原子性地释放 `rm`。`rm` 锁必须以独占方式持有。有关此函数参数的更多详情，请参见 [sleep(9)](/man/man9/sleep.9.md)。

**`rm_assert(struct rmlock *rm, int what)`** 此函数断言 `rm` 锁处于 `what` 所指定的状态。如果断言不成立，且内核编译时启用了 `options INVARIANTS` 和 `options INVARIANT_SUPPORT`，内核将发生 panic。当前支持以下基本断言：此外，可与 `RA_LOCKED`、`RA_RLOCKED` 或 `RA_WLOCKED` 一起指定以下可选标志之一：

**`rms_init(struct rmslock *rms, const char *name)`** 初始化可睡眠的读优先锁 `rms`。`name` 描述用作 msleep(9) 例程的 `wmesg` 参数。在对此锁执行任何其他操作之前，必须调用此函数。

**`rms_rlock(struct rmlock *rm)`** 以读者身份锁定 `rms`。如果有线程独占持有此锁，当前线程将阻塞。

**`rms_wlock(struct rmslock *rms)`** 以写者身份锁定 `rms`。如果锁已被占用，当前线程将阻塞。`rms_wlock` 不能递归调用。

**`rms_runlock(struct rmslock *rms)`** 此函数释放先前由 `rms_rlock` 获取的共享锁。

**`rms_wunlock(struct rmslock *rms)`** 此函数释放先前由 `rms_wlock` 获取的独占锁。

**`rms_destroy(struct rmslock *rms)`** 此函数销毁先前由 `rms_init` 初始化的锁。`rms` 锁必须处于未锁定状态。

## 参见

[locking(9)](/man/man9/locking.9.md), [mutex(9)](/man/man9/mutex.9.md), [panic(9)](/man/man9/panic.9.md), [rwlock(9)](/man/man9/rwlock.9.md), [sema(9)](/man/man9/sema.9.md), [sleep(9)](/man/man9/sleep.9.md), [sx(9)](/man/man9/sx.9.md)

## 历史

这些函数出现在 FreeBSD 7.0 中。

## 作者

`rms_wunlock` 设施由 Stephan Uphoff 编写。本手册页面由 Gleb Smirnoff 为 rwlock 编写，并由 Stephan Uphoff 修改以反映 rmlock。

## 缺陷

`rms_wunlock` 的实现当前未针对单处理器系统进行优化。

当没有写者时，`rm_try_rlock` 也可能瞬时失败，此时另一个读者正在本地 CPU 上更新状态。

`rms_wunlock` 的实现使用系统中所有 rmlock 共享的单个每 CPU 列表。如果 rmlock 变得流行，可能需要散列到多个每 CPU 队列以加速写者锁过程。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/man/man9/rmlock.9.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
