Rust 中的同步原语,如 `Mutex` 和 `RwLock`,是用于在多线程环境中保护共享资源的方式。这些原语确保了只有一个线程可以同时访问被保护的资源,从而避免了竞态条件和其他并发问题。
以下是 `Mutex` 和 `RwLock` 在 Rust 中的基本使用方法:
### 1. 使用 `Mutex`
在 Rust 中,你可以使用 `std::sync::Mutex` 类型来实现互斥锁。下面是一个简单的示例:
```rust
use std::sync::Mutex;
// 定义一个包含互斥锁的计数器结构体
struct Counter {
value: Mutex
}
// 创建一个新的 Counter 实例
let counter = Counter { value: Mutex::new(0) };
// 在一个线程中增加计数器值
std::thread::spawn(move || {
let mut guard = counter.value.lock().unwrap(); // 获取互斥锁的守护者(guard)对象
*guard += 1; // 修改计数器的值
});
// 在另一个线程中获取并修改计数器值
std::thread::spawn(move || {
let mut guard = counter.value.lock().unwrap(); // 再次获取互斥锁的守护者对象(注意:这里会阻塞直到锁被释放)
*guard += 1; // 再次修改计数器的值
});
```
在这个例子中,`Mutex::new(0)` 创建了一个新的互斥锁并初始化为 `0`。然后我们通过 `lock()` 方法获取到这个锁的守护者(guard)对象,并在这个对象上执行我们的操作。由于互斥锁是排他的,所以任何时候只有一个线程可以持有这个锁,这确保了我们的操作是原子的。
### 2. 使用 `RwLock`(读写锁)
`RwLock`(读写锁)允许多个线程同时读取一个资源,但只允许一个线程写入。这在读操作远多于写操作的情况下可以提高性能。下面是 `RwLock` 的使用示例:
```rust
use std::sync::RwLock;
use std::sync::RwLockReadGuard;
use std::sync::RwLockWriteGuard;
// 定义一个包含读写锁的计数器结构体
struct Counter {
value: RwLock
}
// ... 其他代码 ...
// 读取计数器的值(无需锁)
let counter_read = counter.value.read().unwrap(); // 获得读取句柄,不阻塞其他读取者或写者。可同时进行多个读取操作。
let value = *counter_read; // 使用读取句柄读取值。此时不会阻塞其他线程的读取或写入操作。
// 写入计数器的值(需要锁)
std::thread::spawn(move || {
let mut guard = counter.value.write().unwrap(); // 获取写锁,这会阻塞其他读和写操作直到当前写操作完成并释放锁。
*guard += 1; // 修改计数器的值。此时只有当前线程可以访问和修改这个值。其他线程的读和写操作都会被阻塞直到当前写操作完成并释放锁。
});
```
在这个例子中,我们使用 `RwLock` 来保护我们的计数器值。当我们需要读取值时,我们使用 `read()` 方法获取一个读取句柄(`RwLockReadGuard`),这不会阻塞其他读取者或写者。当我们需要写入值时,我们使用 `write()` 方法获取一个写锁(`RwLockWriteGuard`),这会阻塞其他所有读和写操作直到当前写操作完成并释放锁。