面试题答案
一键面试并发原语对赋值运算符行为的影响
- Mutex:
Mutex
(互斥锁)用于保护共享数据,确保同一时间只有一个线程可以访问数据。当使用Mutex
包裹共享数据时,赋值运算符的操作会被限制在Mutex
的锁范围内。只有获取到锁的线程才能对数据进行赋值操作,其他线程必须等待锁的释放。 - Arc:
Arc
(原子引用计数)用于在多个线程间共享数据,它本身并不提供同步机制,但通常与Mutex
等同步原语结合使用。当Arc
与Mutex
一起使用时,Arc
允许数据在多个线程间共享,而Mutex
则控制对数据的访问。赋值运算符操作的是Arc
所指向的数据,这个操作同样要在Mutex
的锁保护下进行。
示例代码
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let shared_data = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let data = Arc::clone(&shared_data);
let handle = thread::spawn(move || {
let mut num = data.lock().unwrap();
*num += 1; // 使用赋值运算符进行数据更新
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Final value: {}", *shared_data.lock().unwrap());
}
在上述代码中:
Arc<Mutex<i32>>
用于在多个线程间共享一个可变的整数。data.lock().unwrap()
获取锁并返回一个可修改的引用,在这个引用上使用赋值运算符*num += 1
对数据进行更新。
竞态条件及避免方法
- 竞态条件:如果没有使用像
Mutex
这样的并发原语,多个线程同时对共享数据进行赋值操作时,可能会导致竞态条件。例如,两个线程同时读取共享数据的值,然后各自进行修改并写回,这样会导致数据丢失更新。 - 避免方法:
- 使用Mutex:如上述示例,通过
Mutex
来保护共享数据,确保同一时间只有一个线程能访问和修改数据,从而避免竞态条件。 - 使用其他同步原语:除了
Mutex
,还可以使用RwLock
(读写锁),在读取操作频繁的场景下,允许多个线程同时读,但写操作依然是独占的,以此来提高并发性能同时避免竞态条件。
- 使用Mutex:如上述示例,通过