use std::sync::{Arc, Mutex};
use std::cell::RefCell;
// 定义包含数据成员的结构体
struct SharedData {
value: i32,
}
fn main() {
// 使用Arc来实现数据的共享,Mutex用于线程安全地访问数据
let shared_data = Arc::new(Mutex::new(RefCell::new(SharedData { value: 0 })));
let mut handles = vec![];
for _ in 0..10 {
// 克隆Arc,以便每个线程都有自己的引用
let data = shared_data.clone();
let handle = std::thread::spawn(move || {
// 锁定Mutex,获取对RefCell的可变引用
let mut inner = data.lock().unwrap();
let mut shared = inner.borrow_mut();
// 修改数据
shared.value += 1;
// 打印修改后的值
println!("Thread modified value: {}", shared.value);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
// 主线程获取并打印最终的值
let final_value = Arc::try_unwrap(shared_data)
.ok()
.unwrap()
.into_inner()
.unwrap()
.borrow()
.value;
println!("Final value: {}", final_value);
}
代码解释
- 结构体定义:
struct SharedData
定义了包含一个 i32
类型数据成员 value
的结构体,这是我们要共享和修改的数据。
- 共享与线程安全工具:
Arc<Mutex<RefCell<SharedData>>>
:
Arc
(原子引用计数)用于在多个线程间安全地共享数据,因为 Arc
内部使用原子操作来管理引用计数,所以是线程安全的。
Mutex
(互斥锁)用于确保同一时间只有一个线程能够访问其内部的数据。当一个线程调用 lock
方法时,如果锁可用,线程会获得锁并可以访问数据;如果锁已被其他线程持有,该线程会被阻塞直到锁被释放。
RefCell
提供内部可变性,允许在不可变引用的情况下修改其内部数据。这在 Rust
中通常用于在运行时检查借用规则,而不是编译时。因为 Mutex
本身是不可变的,所以需要 RefCell
来允许修改内部的 SharedData
。
- 多线程操作:
- 在
for
循环中,通过 Arc::clone
为每个线程创建 shared_data
的克隆,这样每个线程都持有对共享数据的引用。
- 每个线程通过
data.lock().unwrap()
来获取 Mutex
的锁,如果获取成功(unwrap
方法在获取失败时会导致程序 panic),就可以访问内部的 RefCell
。
- 接着通过
inner.borrow_mut()
获取对 SharedData
的可变引用,这样就可以修改 value
成员。
- 主线程等待及获取最终值:
for handle in handles
循环等待所有线程完成。
- 最后,主线程通过
Arc::try_unwrap
尝试获取唯一的 Arc
实例(如果当前 Arc
引用计数为1),然后依次获取 Mutex
内部的 RefCell
,再获取 SharedData
的不可变引用,从而打印最终的 value
值。