数据结构论坛

首页 » 分类 » 问答 » 对比C并发库,Rust简直不要太像
TUhjnbcbe - 2024/5/18 15:58:00

译者

卢鑫旺

将Rust比作C++的小弟的话,相信大家都不会有异议。Rust借鉴了许多C++的设计思想。并发特性亦是如此。

Rust标准库的并发特性与C++11中的特性非常相似:线程、原子操作、锁和互斥量、条件变量等等。然而,在过去的几年中,随着C++17和C++20发布,C++已经获得了相当多新的与并发相关的特性,未来的版本还会有更多的可借鉴之处。

让我们花点时间来回顾一下C++的并发特性,讨论一下这些特性在Rust下会是什么样子的,以及要达到这个效果需要做些什么。

atomic_ref

PR8引入了std::atomic_ref到C++中。它是一种允许你将非原子对象用作原子对象的类型。例如,你可以创建一个atomic_refint,它引用一个常规的int类型的变量,这时你可以使用与原子类型atomicint相同的功能,就跟它是atomicint一样。

在C++中,这需要一个复制大部分原子接口的全新类型,而等效的Rust特性是一行函数:atomic*::from_mut。例如,该函数允许你将mutu32转换为AtomicU32,这是一种在Rust中完全正确的别名形式。C++atomic_ref类型附带了需要手动维护的安全要求。只要你使用atomic_ref来访问对象,那么对该对象的所有访问都必须通过atomic_ref。当仍然存在atomic_ref时直接访问它会导致未定义的行为。然而,在Rust中,这已经由借用检查器完全处理。编译器理解,通过可变地借用u32,在借用结束之前,不允许任何东西直接访问该u32。进入from_mut函数的mutu32的生命周期将作为从中得到的AtomicU32的一部分保留。你可以根据需要复制任意数量的AtomicU32副本,但只有在该引用的所有副本都消失后,原始借用才会结束。

from_mut函数目前不太稳定,但也许是时候稳定它了。

泛型原子类型

在C++中,std::atomic是泛型的:你可以有一个atomic<int>,也可以有atomic<myownstuct>。另一方面,在Rust中,我们只有特定的原子类型:AtomicU32、AtomicBool、AtomicUsize等。

C++的原子类型支持任何大小的对象,无论平台是否支持。对于平台本机原子操作不支持的大小的对象,它会自动返回到基于锁的实现。Rust则只提供平台本机支持的类型。如果你正在用没有64位原子的平台进行编译,则AtomicU64不存在。

这有优点也有缺点。这意味着使用AtomicU64的Rust代码可能无法在某些平台上编译,但也意味着当某些类型默默地返回到一个非常不同的实现时,不会出现与性能相关的意外。这也意味着我们可以假设一个AtomicU64与内存中的u64完全相同,允许使用类似AtomicU64::from_mut的函数。在Rust中使用一个泛型原子类型atomic<T>来处理任何大小的类型可能会很棘手。没有专门化,我们无法使automic<LargeThing>包含Mutex,而不将其包含在automic<SmallThing>中。然而,我们可以做的是将互斥量存储在一个全局HashMap中,由内存地址索引。然后,automic<T>的大小可以与T相同,并在必要时使用此全局HashMap中的互斥量。这就是流行的atomic所做的事情。在Rust标准库中添加这样一个通用的范型automic<T>类型的建议需要讨论它是否应该在no_std程序中使用。常规哈希映射需要分配,这在no_std程序中是不可能的。固定大小的表可能适用于no_std程序,但由于各种原因可能不受欢迎。

Compare-exchange与填充

PR3更改了

1
查看完整版本: 对比C并发库,Rust简直不要太像