1 个不稳定版本
0.1.0 | 2023年3月16日 |
---|
#974 in 并发
18KB
142 行
rendezvous_swap
rendezvous 是线程对之间的执行屏障,但这个 crate 还提供了在同步点交换数据的选项。(术语来自 《信号量小书》)
这主要适用于线程频繁同步的情况。与普通的自旋锁不同,它不使用任何 CAS 指令,仅使用 Acquire
加载和 Release
存储,这意味着它可以在 x86_64
上编译为少量非原子指令。因为这个 crate 使用原子操作进行同步,所以它也是 no_std
。
数据内部以指针进行交换,因此大型结构体交换的成本不高,因此不需要装箱。
在 i5-7200U CPU 上的微基准测试中,交换数据需要不到 100 ns
。
安全性
RendezvousData
包含 unsafe
但在 Miri 运行时所有测试都通过。
示例:同步线程执行
use rendezvous_swap::Rendezvous;
use std::thread;
let (mut my_rendezvous, mut their_rendezvous) = Rendezvous::new();
thread::spawn(move || {
for i in 1..5 {
println!("{i}");
their_rendezvous.wait();
}
});
for i in 1..5 {
println!("{i}");
my_rendezvous.wait();
}
这将打印
1
1
2
2
3
3
4
4
示例:交换线程数据
use std::thread;
use rendezvous_swap::RendezvousData;
let (mut my_rendezvous, mut their_rendezvous) = RendezvousData::new(0, 0);
let handle = thread::spawn(move || {
let borrow = their_rendezvous.swap();
*borrow = 3;
let borrow = their_rendezvous.swap();
assert_eq!(7, *borrow);
});
let borrow = my_rendezvous.swap();
*borrow = 7;
let borrowed_data = my_rendezvous.swap();
assert_eq!(3, *borrowed_data);
示例:安全性
以下代码由于 RendezvousData::swap
提供的引用生命周期有限,无法编译。你会得到熟悉的生命周期错误,就像你正在借用结构体元素一样。这个 crate 是安全的,因为两个线程同时拥有对同一内存位置的互斥引用是不可能的。
use std::thread;
use rendezvous_swap::RendezvousData;
let (mut my_rendezvous, mut their_rendezvous) = RendezvousData::new(0, 0);
let handle = thread::spawn(move || {
their_rendezvous.swap(); // swap return values can be ignored
their_rendezvous.swap();
});
let old_borrow = my_rendezvous.swap(); // first mutable borrow occurs here
let new_borrow = my_rendezvous.swap(); // second mutable borrow occurs here
*old_borrow = 3; // first borrow is later used here