在哪些情况下,Arc<Mutex<T>> 不是 Rust 中在线程间共享数据的最佳方式?

8

根据我的了解,我应该始终选择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());

2
Rust在这方面有一个相当不错的入门指南,允许您选择确切的保证和由此产生的开销。 - Alex Huszagh
2
例如,在某些情况下,您可能希望使用 Arc<RwLock<T>> 而不是 Arc<Mutex<T>> - Alex Huszagh
1个回答

14

线程间共享

除了使用 Arc<T>,我们还可以使用作用域线程(scoped threads)在线程之间共享对象,例如使用 crossbeam::scopeScope::spawn。作用域线程允许我们将借用指针 (&'a T) 发送到在作用域中生成的线程中。作用域保证了线程在引用项被丢弃之前终止。与 Arc<T> 相比,借用指针没有运行时开销(Arc<T> 需要更多的内存,并需要使用原子指令来维护引用计数器)。

跨线程变异

Mutex<T> 是确保最多只有一个线程可以同时变异值的最基本通用包装器。 Mutex<T> 有一个缺点:如果有许多只想读取互斥锁中的值的线程,则它们不能同时执行,即使这样做是安全的。 RwLock<T> 通过允许多个并发读取器(同时仍然确保编写器具有独占访问权)来解决这个问题。

AtomicUsize 这样的原子类型也允许跨线程变异,但仅适用于小值(8、16、32或64位,一些处理器支持对128位值进行原子操作,但标准库尚未公开该操作;请参见 atomic::Atomic)。例如,您可以使用 Arc<AtomicUsize> 而不是 Arc<Mutex<usize>>。原子类型不需要锁定,但它们通过原子机器指令进行操作。原子指令集与非原子指令集略有不同,因此从非原子类型切换到原子类型可能并不总是“即插即用”的替代品。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接