面试题答案
一键面试- 使用
Arc
和Mutex
实现多线程共享可变数据结构:- 首先,引入必要的
rust
库:
use std::sync::{Arc, Mutex}; use std::thread;
- 定义复杂的数据结构,例如嵌套结构体:
struct InnerStruct { data: i32, } struct OuterStruct { inner: InnerStruct, }
- 在多线程间共享并可变地操作这个数据结构:
fn main() { let shared_data = Arc::new(Mutex::new(OuterStruct { inner: InnerStruct { data: 0 }, })); let mut handles = vec![]; for _ in 0..10 { let data_clone = shared_data.clone(); let handle = thread::spawn(move || { let mut data = data_clone.lock().unwrap(); data.inner.data += 1; }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } let final_data = shared_data.lock().unwrap(); println!("Final data: {}", final_data.inner.data); }
- 首先,引入必要的
- 处理生命周期和所有权问题:
- 所有权:
Arc
(原子引用计数)负责管理数据结构的所有权。通过Arc::clone
方法可以复制引用计数,而不会复制实际的数据。例如,在let data_clone = shared_data.clone();
这一行,data_clone
和shared_data
指向同一个Mutex<OuterStruct>
实例,它们共享所有权。Mutex
内部的数据(即OuterStruct
)的所有权由Mutex
持有,而Mutex
的所有权由Arc
持有。当最后一个Arc
实例被销毁时,Mutex
及其内部的数据也会被销毁。
- 生命周期:
- 由于
Arc
和Mutex
都实现了Send
和Sync
trait,所以它们可以安全地在多线程间传递。 - 在获取
Mutex
内部数据的可变引用时,通过lock
方法返回的Result<MutexGuard<'_, T>, PoisonError<MutexGuard<'_, T>>>
来处理。其中MutexGuard
是一个智能指针,它实现了Deref
和DerefMut
trait,使得可以像操作普通引用一样操作内部数据。同时,MutexGuard
的生命周期与lock
调用所在的作用域相关,当作用域结束时,MutexGuard
会自动释放锁,保证了数据的一致性和内存安全。在上述代码中,let mut data = data_clone.lock().unwrap();
获取到的data
的生命周期局限于线程闭包内的代码块,当闭包结束时,data
(即MutexGuard
)被销毁,锁被释放。这样就避免了在多线程环境下可能出现的内存安全问题,如数据竞争和悬空指针等。
- 由于
- 所有权: