面试题答案
一键面试在Rust并行编程中,确保数据在线程间共享时的线程安全性,通常可以使用以下几种方式:
- Mutex(互斥锁):
Mutex
(Mutual Exclusion的缩写)用于保护共享数据,确保同一时间只有一个线程可以访问数据。- 当一个线程想要访问被
Mutex
保护的数据时,它必须先获取锁。如果锁已经被其他线程持有,该线程会被阻塞,直到锁被释放。 - 例如,假设有一个共享的计数器,多个线程需要对其进行递增操作:
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Final counter value: {}", *counter.lock().unwrap());
}
- 在这个例子中,`Arc`(原子引用计数)用于在多个线程间共享`Mutex`实例,`Mutex`保护着计数器`num`。每个线程通过`lock()`方法获取锁,对计数器进行递增操作,操作完成后锁会自动释放(因为`lock()`返回的是一个实现了`Drop` trait的智能指针,离开作用域时会自动释放锁)。
2. RwLock(读写锁):
- RwLock
允许多个线程同时进行读操作,但只允许一个线程进行写操作。
- 读操作可以并发执行,因为它们不会修改数据,不会产生数据竞争。写操作则需要独占访问,以确保数据的一致性。
- 例如,假设有一个共享的只读数据结构,多个线程可能会读取它,偶尔会有一个线程更新它:
use std::sync::{Arc, RwLock};
use std::thread;
fn main() {
let data = Arc::new(RwLock::new(String::from("initial value")));
let mut handles = vec![];
// 启动多个读线程
for _ in 0..5 {
let data = Arc::clone(&data);
let handle = thread::spawn(move || {
let value = data.read().unwrap();
println!("Read value: {}", value);
});
handles.push(handle);
}
// 启动一个写线程
let data = Arc::clone(&data);
let write_handle = thread::spawn(move || {
let mut value = data.write().unwrap();
*value = String::from("new value");
});
handles.push(write_handle);
for handle in handles {
handle.join().unwrap();
}
let final_value = data.read().unwrap();
println!("Final value: {}", final_value);
}
- 在这个例子中,`Arc`用于共享`RwLock`实例,读线程通过`read()`方法获取读锁,写线程通过`write()`方法获取写锁。读锁允许多个线程同时读取数据,而写锁会阻止其他读线程和写线程,直到写操作完成。