Rust原子操作库atomig的使用:高效并发编程与多线程安全访问的原子类型实现
Rust原子操作库atomig的使用:高效并发编程与多线程安全访问的原子类型实现
提供通用的便捷std
原子操作。
提供可以与原始类型和自定义类型一起使用的Atomic<T>
。但是,它仅适用于实际可以使用原子操作的类型:不用于其他类型的基于锁的回退!此crate基于std
的原子操作,因此不包含任何unsafe
代码!默认情况下,此crate没有任何依赖项。如果启用serde
功能,则此crate将依赖于serde
,并在适当时为Atomic<T>
实现Serialize
/Deserialize
,使用顺序一致性排序。
原始类型的简单示例:
use atomig::{Atomic, Ordering};
let x = Atomic::new(27); // `Atomic<i32>`
x.store(39, Ordering::SeqCst);
这适用于几乎所有原始类型,包括f32
、f64
和char
,但也适用于std::ptr::NonNull
和std::num::NonZero
等类型。
您可以自动为自定义枚举或结构类型派生Atom
,以便在Atomic<T>
中使用它们。但是,存在一些限制。
// 需要'derive'功能:
// atomig = { version = "_", features = ["derive"] }
use atomig::{Atom, Atomic, Ordering};
#[derive(Atom)]
#[repr(u8)]
enum Animal { Dog, Cat, Fox }
let animal = Atomic::new(Animal::Cat);
animal.store(Animal::Fox, Ordering::SeqCst);
#[derive(Atom)]
struct Port(u16);
let port = Atomic::new(Port(80));
port.store(Port(8080), Ordering::SeqCst);
完整示例代码
// 基本使用示例
use atomig::{Atomic, Ordering};
fn main() {
// 创建原子整数
let atomic_int = Atomic::new(0);
// 多线程环境下安全地修改值
atomic_int.store(42, Ordering::SeqCst);
// 读取当前值
let value = atomic_int.load(Ordering::SeqCst);
println!("Atomic integer value: {}", value);
// 原子交换操作
let previous = atomic_int.swap(100, Ordering::SeqCst);
println!("Previous value: {}, New value: {}", previous, atomic_int.load(Ordering::SeqCst));
}
// 自定义类型示例(需要derive功能)
#[cfg(feature = "derive")]
mod custom_types {
use atomig::{Atom, Atomic, Ordering};
#[derive(Atom, Debug, PartialEq)]
#[repr(u8)]
enum Status {
Idle,
Running,
Stopped,
Error
}
#[derive(Atom, Debug)]
struct Counter(u32);
fn custom_type_demo() {
// 枚举原子类型
let status = Atomic::new(Status::Idle);
status.store(Status::Running, Ordering::SeqCst);
// 结构体原子类型
let counter = Atomic::new(Counter(0));
counter.store(Counter(42), Ordering::SeqCst);
}
}
// 多线程示例
use std::thread;
use std::sync::Arc;
fn concurrent_example() {
let atomic_counter = Arc::new(Atomic::new(0));
let mut handles = vec![];
// 创建10个线程并发增加计数器
for _ in 0..10 {
let counter = Arc::clone(&atomic_counter);
let handle = thread::spawn(move || {
for _ in 0..1000 {
// 使用原子操作确保线程安全
let current = counter.load(Ordering::SeqCst);
counter.store(current + 1, Ordering::SeqCst);
}
});
handles.push(handle);
}
// 等待所有线程完成
for handle in handles {
handle.join().unwrap();
}
println!("Final counter value: {}", atomic_counter.load(Ordering::SeqCst));
}
许可证
根据Apache许可证2.0版或MIT许可证中的任一许可,由您选择。除非您明确声明,否则根据Apache-2.0许可证定义,您为包含在此项目中而有意提交的任何贡献均应按照上述双重许可,不附加任何其他条款或条件。
1 回复
Rust原子操作库atomig
的使用指南
介绍
atomig
是一个轻量级的Rust原子操作库,提供了跨平台的原子类型实现。该库专注于为多线程环境下的并发编程提供安全、高效的原子操作支持,帮助开发者避免数据竞争和并发访问问题。
主要特性
- 提供多种原子类型(AtomicBool、AtomicI32、AtomicU64等)
- 支持多种内存排序(Relaxed、Acquire、Release等)
- 跨平台兼容性
- 零成本抽象
安装方法
在Cargo.toml中添加依赖:
[dependencies]
atomig = "0.3"
基本使用方法
1. 创建原子变量
use atomig::Atomic;
let atomic_bool = Atomic::new(false);
let atomic_int = Atomic::new(0i32);
2. 基本原子操作
use atomig::{Atomic, Ordering};
let atomic = Atomic::new(5);
// 存储值
atomic.store(10, Ordering::SeqCst);
// 加载值
let value = atomic.load(Ordering::SeqCst);
println!("当前值: {}", value);
// 比较并交换
let result = atomic.compare_exchange(
10,
15,
Ordering::SeqCst,
Ordering::Relaxed
);
3. 原子算术操作
let atomic = Atomic::new(0u32);
// 原子加法
let prev = atomic.fetch_add(5, Ordering::SeqCst);
println!("加法前值: {}, 加法后值: {}", prev, atomic.load(Ordering::SeqCst));
// 原子减法
atomic.fetch_sub(2, Ordering::SeqCst);
// 原子与操作
atomic.fetch_and(0xFF, Ordering::SeqCst);
4. 多线程安全示例
use std::sync::Arc;
use std::thread;
use atomig::{Atomic, Ordering};
let counter = Arc::new(Atomic::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
for _ in 0..1000 {
counter.fetch_add(1, Ordering::SeqCst);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("最终计数: {}", counter.load(Ordering::SeqCst));
5. 内存排序示例
use atomig::{Atomic, Ordering};
let data = Atomic::new(0);
let flag = Atomic::new(false);
// 线程1:发布数据
data.store(42, Ordering::Relaxed);
flag.store(true, Ordering::Release);
// 线程2:获取数据
while !flag.load(Ordering::Acquire) {
// 自旋等待
}
let value = data.load(Ordering::Relaxed);
println!("获取到的数据: {}", value);
完整示例demo
use std::sync::Arc;
use std::thread;
use atomig::{Atomic, Ordering};
fn main() {
// 示例1:基本原子操作
println!("=== 基本原子操作示例 ===");
let atomic_counter = Atomic::new(0i32);
// 存储新值
atomic_counter.store(10, Ordering::SeqCst);
// 加载当前值
let current_value = atomic_counter.load(Ordering::SeqCst);
println!("当前计数值: {}", current_value);
// 比较并交换操作
match atomic_counter.compare_exchange(
10,
15,
Ordering::SeqCst,
Ordering::Relaxed
) {
Ok(prev) => println!("比较交换成功,之前的值: {}", prev),
Err(current) => println!("比较交换失败,当前值: {}", current),
}
// 示例2:原子算术操作
println!("\n=== 原子算术操作示例 ===");
let atomic_number = Atomic::new(0u32);
// 原子加法
let prev_add = atomic_number.fetch_add(5, Ordering::SeqCst);
println!("加法前: {}, 加法后: {}", prev_add, atomic_number.load(Ordering::SeqCst));
// 原子减法
let prev_sub = atomic_number.fetch_sub(2, Ordering::SeqCst);
println!("减法前: {}, 减法后: {}", prev_sub, atomic_number.load(Ordering::SeqCst));
// 原子与操作
atomic_number.fetch_and(0b1111, Ordering::SeqCst);
println!("与操作后: {}", atomic_number.load(Ordering::SeqCst));
// 示例3:多线程计数器
println!("\n=== 多线程计数器示例 ===");
let shared_counter = Arc::new(Atomic::new(0));
let mut threads = vec![];
// 创建10个线程,每个线程增加计数器100次
for _ in 0..10 {
let counter_ref = Arc::clone(&shared_counter);
let thread = thread::spawn(move || {
for _ in 0..100 {
counter_ref.fetch_add(1, Ordering::SeqCst);
}
});
threads.push(thread);
}
// 等待所有线程完成
for thread in threads {
thread.join().unwrap();
}
println!("最终计数器值: {}", shared_counter.load(Ordering::SeqCst));
// 示例4:内存排序示例
println!("\n=== 内存排序示例 ===");
let data = Atomic::new(0);
let flag = Atomic::new(false);
// 模拟线程1:发布数据
data.store(42, Ordering::Relaxed);
flag.store(true, Ordering::Release);
println!("线程1: 数据已发布");
// 模拟线程2:获取数据
while !flag.load(Ordering::Acquire) {
// 自旋等待标志位
std::thread::yield_now();
}
let received_data = data.load(Ordering::Relaxed);
println!("线程2: 获取到的数据: {}", received_data);
}
注意事项
- 根据具体场景选择合适的内存排序级别
- 避免过度使用原子操作,可能影响性能
- 在需要时考虑使用Mutex或其他同步原语
性能建议
- 对于计数器等简单场景,优先使用Relaxed排序
- 需要严格同步时使用SeqCst排序
- 考虑使用fetch_update进行复杂操作
这个库为Rust开发者提供了简单易用的原子操作接口,是构建高性能并发应用的理想选择。