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

这适用于几乎所有原始类型,包括f32f64char,但也适用于std::ptr::NonNullstd::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);
}

注意事项

  1. 根据具体场景选择合适的内存排序级别
  2. 避免过度使用原子操作,可能影响性能
  3. 在需要时考虑使用Mutex或其他同步原语

性能建议

  • 对于计数器等简单场景,优先使用Relaxed排序
  • 需要严格同步时使用SeqCst排序
  • 考虑使用fetch_update进行复杂操作

这个库为Rust开发者提供了简单易用的原子操作接口,是构建高性能并发应用的理想选择。

回到顶部