面试题答案
一键面试多线程并发访问共享内存问题
- 数据竞争(Data Race):多个线程同时读写共享内存,可能导致数据不一致或未定义行为。例如,一个线程读取数据的同时另一个线程修改该数据,可能读取到部分修改的数据。
- 竞态条件(Race Condition):线程执行顺序依赖于不确定因素,导致程序行为不可预测。比如,多个线程竞争对共享内存的初始化,可能导致初始化顺序错误。
使用Rust同步原语解决问题
- Mutex(互斥锁):
- 原理:Mutex允许同一时间只有一个线程访问共享资源。当一个线程获取到锁时,其他线程必须等待锁释放才能访问。
- 示例:
use std::sync::{Arc, Mutex};
fn main() {
let shared_data = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let data = shared_data.clone();
let handle = std::thread::spawn(move || {
let mut num = data.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let result = shared_data.lock().unwrap();
println!("Final value: {}", *result);
}
在这个例子中,Arc<Mutex<i32>>
用于在多个线程间共享一个 i32
类型的数据。每个线程通过 lock
方法获取锁,修改数据后自动释放锁。
- RwLock(读写锁):
- 原理:RwLock允许多个线程同时读共享资源,但只允许一个线程写。写操作需要独占锁,读操作可以并发进行,前提是没有写操作。
- 示例:
use std::sync::{Arc, RwLock};
fn main() {
let shared_data = Arc::new(RwLock::new(0));
let mut read_handles = vec![];
for _ in 0..10 {
let data = shared_data.clone();
let handle = std::thread::spawn(move || {
let num = data.read().unwrap();
println!("Read value: {}", *num);
});
read_handles.push(handle);
}
let write_handle = std::thread::spawn(move || {
let mut num = shared_data.write().unwrap();
*num += 1;
});
for handle in read_handles {
handle.join().unwrap();
}
write_handle.join().unwrap();
let result = shared_data.read().unwrap();
println!("Final value: {}", *result);
}
此例中,多个读线程可以同时读取共享数据,而写线程需要获取写锁才能修改数据,保证了数据一致性。