Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .markdownlint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"default": true,
"MD013": false,
"MD033": false
}
19 changes: 19 additions & 0 deletions 4_Building_Our_Own_Spin_Lock.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# 第四章:构建我们自己的自旋锁

对普通互斥锁(参见[第一章中的“锁:互斥锁和读写锁”](./1_Basic_of_Rust_Concurrency.md#锁互斥锁和读写锁))进行加锁时,如果互斥锁已经被锁定,线程将被置于睡眠状态。这避免在等待锁被释放时浪费资源。如果一个锁只会被短暂地持有,并且锁定它的线程可以在不同的处理器核心并发地运行,那么线程最好反复尝试锁定它而不实际进入睡眠态。

自旋锁是能够做到这一点的 mutex。试图锁定一个已经锁定的 mutex 将导致*忙碌循环*或者*自旋*:一遍又一遍的尝试。直到它成功。这可能浪费处理器周期,但有时会导致锁定时的延迟更低。

> 在某些平台上,许多现实世界中的 mutex 实现,包括 `std::sync::Mutex`,在告诉操作系统将线程置于睡眠状态之前,短暂地表现得像一个自旋锁。这是为了将两者的优点结合起来,尽管具体使用情况是否有益,这取决于特定的用例。

在该章节总,我们将建造我们自己的 `SpinLock` 类型,应用我们已经在第 [2](./2_Atomics.md) 章和第 [3](./3_Memory_Ordering.md) 章学习的,并且了解如何使用 Rust 的类型系统为我们的 SpinLock 用户提供安全且有用的接口。

## 一个最小实现

## 一个不安全的自旋锁
Expand All @@ -8,6 +16,17 @@

## 总结

* 自旋锁是在等待时忙碌循环或自选的 mutex。
* 自旋可以减少延迟,但也可能浪费时钟周期并降低性能。
* 自旋循环提示(`spin::hint::spin_loop()`)可以用于通知处理器自旋循环,这可能增加它的效率。
* `SpinLock<T>` 只需使用 `AtomicBool` 和 `UnsafeCell<T>` 即可实现,后者是*内部可变性*所必需的(见[第 1 章中的“内部可变性”](./1_Basic_of_Rust_Concurrency.md#内部可变性))。
* 在解锁和锁定之间的 *happens-before 关系*是防止*数据竞争*的必要条件,否则会导致未定义行为。
* *Acquire* 和 *Release* 内存排序对这个用例是极合适的。
* 当做出必要的未检查的假设以避免未定义的行为时,可以通过将函数标记为不安全来将责任转移到调用者。
* `Deref` 和 `DerefMut` trait 可用于使类型像引用一样,透明地提供对另一个对象的访问。
* `Drop` trait 可以用于在对象被 drop 时,做一些事情,例如当它超出作用域或者它被传递给 `drop()`。
* *锁 guard* 是一种特殊类型的有用设计模式,它被用于表示对锁定的锁的(安全)访问。由于 `Deref` trait,这种类型通常与引用的行为相似,并通过 `Drop` trait 实现自动解锁。

<p style="text-align: center; padding-block-start: 5rem;">
<a href="./5_Building_Our_Own_Channels.html">下一篇,第五章:构建我们自己的 Channel</a>
</p>