根据我的了解,我应该始终选择Arc<T>
跨线程共享读访问和跨线程Arc<Mutex<T>>
共享写访问。在某些情况下,我不想使用Arc<T>
/Arc<Mutex<T>>
而是做一些完全不同的事情吗?例如做这样的事情:
unsafe impl Sync for MyStruct {}
unsafe impl Send for MyStruct {}
let shared_data_for_writing = Arc::from(MyStruct::new());
Run Code Online (Sandbox Code Playgroud)
此外Arc<T>
,我们可以使用作用域线程跨线程共享对象,例如使用crossbeam::scope
和Scope::spawn
。作用域线程允许我们将借用的指针 ( &'a T
)发送到作用域中产生的线程。范围保证线程将在引用对象被删除之前终止。与Arc<T>
(Arc<T>
占用更多内存并需要使用原子指令维护引用计数器)相比,借用指针没有运行时开销。
Mutex<T>
是最基本的通用包装器,用于确保在任何给定时间最多有一个线程可以改变一个值。Mutex<T>
有一个缺点:如果有许多线程只想读取互斥锁中的值,则它们不能同时执行,即使这样做是安全的。RwLock<T>
通过允许多个并发读取器(同时仍确保写入器具有独占访问权限)来解决此问题。
原子类型,例如AtomicUsize
也允许跨线程变异,但仅适用于小值(8、16、32 或 64 位 - 一些处理器支持对 128 位值的原子操作,但标准库中尚未公开;请参阅atomic::Atomic
) . 例如,Arc<Mutex<usize>>
您可以使用来代替Arc<AtomicUsize>
。原子类型不需要锁定,但它们通过原子机器指令进行操作。原子指令集与非原子指令集略有不同,因此从非原子类型切换到原子类型可能并不总是“直接替换”。