Skip to content

Ch 34: std::sync::Arc - 原子引用计数

Arc(Atomically Reference Counted)是原子引用计数的智能指针,用于跨线程共享所有权。与Rc不同,Arc使用原子操作保证线程安全。

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));
}
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();
}
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]
}

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());
}
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());
}

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);
}
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!("转换失败");
}
}

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));
}
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();
}
}
  1. 性能开销:原子操作比普通操作慢,避免不必要的Arc克隆
  2. 不要滥用Arc:只在需要共享所有权时使用
  3. 配合锁使用:Arc本身不可变,需要Mutex/RwLock实现可变
  4. Weak计数:Weak不影响强引用计数,但持有时会阻止释放
  5. 不要循环引用:使用Weak避免Arc间的循环引用导致内存泄漏

std::sync::Arc核心API:

  • Arc::new() - 创建原子引用计数指针
  • Arc::clone() - 克隆(增加引用计数)
  • Arc::strong_count() - 强引用计数
  • Arc::weak_count() - 弱引用计数
  • Arc::downgrade() - 创建Weak
  • Arc::make_mut() - 独占访问(COW)
  • Arc::downcast() - 类型转换

Arc是Rust多线程共享所有权的首选:

  • Arc<T> - 不可变共享
  • Arc<Mutex<T>> - 可变共享
  • Arc<RwLock<T>> - 读多写少场景
  • Weak<T> - 避免循环引用