Ch 34: std::sync::Arc - 原子引用计数
Arc(Atomically Reference Counted)是原子引用计数的智能指针,用于跨线程共享所有权。与Rc不同,Arc使用原子操作保证线程安全。
2. 基本用法
Section titled “2. 基本用法”use std::sync::Arc;use std::thread;
fn main() { let data = Arc::new(vec![1, 2, 3]);
// 克隆Arc(增加引用计数) let data2 = Arc::clone(&data);
// 在新线程中使用 let handle = thread::spawn(move || { println!("子线程数据: {:?}", data2); });
// 主线程继续使用原Arc println!("主线程数据: {:?}", data);
handle.join().unwrap();
println!("引用计数: {}", Arc::strong_count(&data));}3. Arc vs Rc
Section titled “3. Arc vs Rc”use std::sync::Arc;use std::rc::Rc;use std::thread;
fn main() { // Rc不是线程安全的(编译错误) // let rc = Rc::new(vec![1, 2, 3]); // thread::spawn(move || { // println!("{:?}", rc); // 错误! // });
// Arc是线程安全的 let arc = Arc::new(vec![1, 2, 3]); thread::spawn(move || { println!("Arc: {:?}", arc); }).join().unwrap();}4. 方法签名
Section titled “4. 方法签名”impl<T> Arc<T> { pub fn new(t: T) -> Arc<T> pub fn try_new(t: T) -> Result<Arc<T>, AllocError> pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Arc<T>
pub fn as_ref(&self) -> &T pub fn borrow(&self) -> &T
pub fn clone(&self) -> Arc<T> pub fn strong_count(&self) -> usize pub fn weak_count(&self) -> usize
pub fn downcast<T: 'static>(&self) -> Result<Arc<T>, Arc<dyn Any + Send + Sync>>
// 注意:Arc<T>没有直接提供可变引用,需要内部可变性}
impl<T> Arc<[T]> { pub fn make_mut(&mut self) -> &mut [T]}5. Arc + Mutex / RefCell 实现可变
Section titled “5. Arc + Mutex / RefCell 实现可变”Arc本身不可变,需要配合Mutex或RwLock实现跨线程可变:
use std::sync::{Arc, Mutex};use std::thread;
fn main() { let data = Arc::new(Mutex::new(vec![1, 2, 3]));
let mut handles = vec![];
// 多个线程修改数据 for i in 0..5 { let data = Arc::clone(&data); let handle = thread::spawn(move || { let mut v = data.lock().unwrap(); v.push(i); }); handles.push(handle); }
for handle in handles { handle.join().unwrap(); }
println!("最终数据: {:?}", data.lock().unwrap());}6. Arc + RwLock 读多写少场景
Section titled “6. Arc + RwLock 读多写少场景”use std::sync::{Arc, RwLock};use std::thread;
fn main() { let data = Arc::new(RwLock::new(vec![1, 2, 3]));
let readers: Vec<_> = (0..3).map(|_| { let data = Arc::clone(&data); thread::spawn(move || { let r = data.read().unwrap(); println!("读: {:?}", r); }) }).collect();
let writer = { let data = Arc::clone(&data); thread::spawn(move || { let mut w = data.write().unwrap(); w.push(4); println!("写入完成"); }) };
for h in readers { h.join().unwrap(); } writer.join().unwrap();
println!("最终: {:?}", data.read().unwrap());}7. Arc::make_mut - 独占访问
Section titled “7. Arc::make_mut - 独占访问”make_mut在需要可变引用时会克隆数据(copy-on-write):
use std::sync::Arc;
fn main() { let data = Arc::new(vec![1, 2, 3]);
// 获取可变引用(会克隆内部数据) let mutable_data = Arc::make_mut(&mut data.clone());
// 现在有两个独立的Vec mutable_data.push(4); println!("修改后的: {:?}", mutable_data); println!("原Arc: {:?}", data);}8. Arc::downcast - 类型转换
Section titled “8. Arc::downcast - 类型转换”use std::sync::Arc;use std::any::Any;
fn main() { // 创建dyn Trait对象 let trait_obj: Arc<dyn std::fmt::Debug + Send + Sync> = Arc::new(vec![1, 2, 3]);
// 尝试向下转型 if let Ok(vec) = trait_obj.downcast::<Vec<i32>>() { println!("转换成功: {:?}", vec); } else { println!("转换失败"); }}9. Weak - 弱引用
Section titled “9. Weak - 弱引用”Weak不拥有对象,用于避免循环引用:
use std::sync::{Arc, Weak};use std::thread;
fn main() { let data = Arc::new(vec![1, 2, 3]); let weak = Arc::downgrade(&data);
println!("强引用计数: {}", Arc::strong_count(&data)); println!("弱引用计数: {}", Arc::weak_count(&data));
let handle = thread::spawn(move || { // 通过Weak尝试升级为Arc if let Some(strong) = weak.upgrade() { println!("升级成功: {:?}", strong); } else { println!("数据已被释放"); } });
handle.join().unwrap();
// drop强引用后数据可能释放 drop(data);
println!("强引用计数: {}", Arc::strong_count(&data));}10. 常用模式
Section titled “10. 常用模式”use std::sync::{Arc, Mutex};use std::thread;
struct Config { timeout: u64,}
fn main() { // 配置共享 let config = Arc::new(Mutex::new(Config { timeout: 30 }));
// 多个工作线程使用同一配置 let workers: Vec<_> = (0..5).map(|i| { let config = Arc::clone(&config); thread::spawn(move || { let cfg = config.lock().unwrap(); println!("Worker {} timeout: {}", i, cfg.timeout); }) }).collect();
for w in workers { w.join().unwrap(); }}11. 注意事项
Section titled “11. 注意事项”- 性能开销:原子操作比普通操作慢,避免不必要的Arc克隆
- 不要滥用Arc:只在需要共享所有权时使用
- 配合锁使用:
Arc本身不可变,需要Mutex/RwLock实现可变 - Weak计数:
Weak不影响强引用计数,但持有时会阻止释放 - 不要循环引用:使用
Weak避免Arc间的循环引用导致内存泄漏
12. 总结
Section titled “12. 总结”std::sync::Arc核心API:
Arc::new()- 创建原子引用计数指针Arc::clone()- 克隆(增加引用计数)Arc::strong_count()- 强引用计数Arc::weak_count()- 弱引用计数Arc::downgrade()- 创建WeakArc::make_mut()- 独占访问(COW)Arc::downcast()- 类型转换
Arc是Rust多线程共享所有权的首选:
Arc<T>- 不可变共享Arc<Mutex<T>>- 可变共享Arc<RwLock<T>>- 读多写少场景Weak<T>- 避免循环引用