Rust原子枚举操作库portable_atomic_enum的使用,实现跨平台线程安全的枚举原子操作

Rust原子枚举操作库portable_atomic_enum的使用,实现跨平台线程安全的枚举原子操作

portable_atomic_enum是一个从atomic_enum分叉出来的库,它可选地使用portable-atomic来支持更多目标平台。该库提供了一个属性宏来创建C风格枚举的原子包装器。

示例

# use atomic_enum::atomic_enum;
# use std::sync::atomic::Ordering;
#[atomic_enum]
#[derive(Clone, Copy, Debug, PartialEq)]
enum CatState {
    Dead = 0,
    BothDeadAndAlive,
    Alive,
}

let state = AtomicCatState::new(CatState::Dead);
state.store(CatState::Alive, Ordering::Relaxed);
assert_eq!(state.load(Ordering::Relaxed), CatState::Alive);

该属性宏不会使用或生成任何不安全代码,并且可以在#[no_std]环境中使用。

完整示例代码

下面是一个更完整的示例,展示如何在多线程环境中使用portable_atomic_enum:

use portable_atomic_enum::atomic_enum;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::thread;

// 定义一个状态枚举
#[atomic_enum]
#[derive(Clone, Copy, Debug, PartialEq)]
enum ThreadState {
    Idle = 0,
    Running,
    Finished,
}

fn main() {
    // 创建原子状态变量
    let state = Arc::new(AtomicThreadState::new(ThreadState::Idle));
    
    // 克隆Arc用于线程
    let state_clone = Arc::clone(&state);
    
    let handle = thread::spawn(move || {
        // 线程开始时设置状态为Running
        state_clone.store(ThreadState::Running, Ordering::SeqCst);
        
        // 模拟工作
        thread::sleep(std::time::Duration::from_secs(1));
        
        // 工作完成后设置状态为Finished
        state_clone.store(ThreadState::Finished, Ordering::SeqCst);
    });
    
    // 主线程监控状态变化
    loop {
        let current_state = state.load(Ordering::SeqCst);
        println!("当前状态: {:?}", current_state);
        
        if current_state == ThreadState::Finished {
            break;
        }
        
        thread::sleep(std::time::Duration::from_millis(200));
    }
    
    handle.join().unwrap();
    println!("线程完成!");
}

Cargo特性

  • portable-atomic: 使用portable-atomic作为原子类型的polyfill

特点

  1. 内部使用AtomicUsize存储枚举值
  2. 原子操作与AtomicUsize的等效操作具有相同的语义
  3. 不需要任何不安全代码
  4. 支持#[no_std]环境
  5. 跨平台支持

要使用这个库,只需在Cargo.toml中添加依赖:

portable_atomic_enum = "0.3.1"

1 回复

Rust原子枚举操作库portable_atomic_enum使用指南

portable_atomic_enum是一个Rust库,它提供了跨平台的线程安全枚举原子操作。这个库在需要以原子方式操作枚举值时特别有用,尤其是在多线程环境中。

特性

  • 提供枚举类型的原子操作
  • 跨平台支持
  • 线程安全
  • 类似标准库std::sync::atomic的API风格

安装

Cargo.toml中添加依赖:

[dependencies]
portable_atomic_enum = "0.1"

基本用法

定义可原子操作的枚举

首先,你需要定义一个枚举并使用#[derive(Atomic)]宏:

use portable_atomic_enum::Atomic;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Atomic)]
enum State {
    Idle,
    Running,
    Paused,
    Stopped,
}

创建原子枚举变量

use portable_atomic_enum::AtomicEnum;

let atomic_state = AtomicEnum::new(State::Idle);

基本操作

// 存储值
atomic_state.store(State::Running, std::sync::atomic::Ordering::SeqCst);

// 加载值
let current_state = atomic_state.load(std::sync::atomic::Ordering::SeqCst);
println!("Current state: {:?}", current_state);

// 交换值
let previous_state = atomic_state.swap(State::Paused, std::sync::atomic::Ordering::SeqCst);
println!("Previous state: {:?}", previous_state);

比较并交换(CAS)

let mut expected = State::Paused;
loop {
    match atomic_state.compare_exchange(
        expected,
        State::Running,
        std::sync::atomic::Ordering::SeqCst,
        std::sync::atomic::Ordering::Relaxed,
    ) {
        Ok(_) => break,
        Err(actual) => expected = actual,
    }
}

高级用法

使用fetch_update

atomic_state.fetch_update(
    std::sync::atomic::Ordering::SeqCst,
    std::sync::atomic::Ordering::Relaxed,
    |state| match state {
        State::Idle => Some(State::Running),
        State::Running => Some(State::Paused),
        _ => None,
    },
);

多线程示例

use std::sync::Arc;
use std::thread;

let shared_state = Arc::new(AtomicEnum::new(State::Idle));

let threads: Vec<_> = (0..4)
    .map(|i| {
        let state = shared_state.clone();
        thread::spawn(move || {
            // 每个线程尝试将状态改为Running
            state.compare_exchange(
                State::Idle,
                State::Running,
                std::sync::atomic::Ordering::SeqCst,
                std::sync::atomic::Ordering::Relaxed,
            ).ok();
            println!("Thread {} set state to Running", i);
        })
    })
    .collect();

for t in threads {
    t.join().unwrap();
}

println!("Final state: {:?}", shared_state.load(std::sync::atomic::Ordering::SeqCst));

内存顺序

和标准库的原子类型一样,portable_atomic_enum支持多种内存顺序:

  • Relaxed
  • Acquire
  • Release
  • AcqRel
  • SeqCst

注意事项

  1. 枚举的大小不能超过指针大小(通常64位系统上是8字节)
  2. 枚举的表示必须是#[repr(C)]#[repr(integer_type)]Atomic派生宏会自动处理
  3. 对于复杂枚举,可能需要手动实现Atomic trait

portable_atomic_enum为Rust中的枚举提供了简单而强大的原子操作能力,特别适合状态机实现和多线程环境下的状态管理。

完整示例代码

use portable_atomic_enum::{Atomic, AtomicEnum};
use std::sync::{Arc, atomic::Ordering};
use std::thread;

// 定义原子枚举
#[derive(Debug, Clone, Copy, PartialEq, Eq, Atomic)]
enum TaskState {
    Pending,
    Processing,
    Completed,
    Failed,
}

fn main() {
    // 创建原子枚举实例
    let atomic_task = AtomicEnum::new(TaskState::Pending);
    
    // 基本操作示例
    println!("初始状态: {:?}", atomic_task.load(Ordering::SeqCst));
    
    atomic_task.store(TaskState::Processing, Ordering::SeqCst);
    println!("存储后状态: {:?}", atomic_task.load(Ordering::SeqCst));
    
    let prev = atomic_task.swap(TaskState::Completed, Ordering::SeqCst);
    println!("交换后前一个状态: {:?}", prev);
    
    // CAS操作示例
    let result = atomic_task.compare_exchange(
        TaskState::Completed,
        TaskState::Pending,
        Ordering::SeqCst,
        Ordering::Relaxed,
    );
    println!("CAS操作结果: {:?}", result);
    
    // 多线程示例
    let shared_task = Arc::new(AtomicEnum::new(TaskState::Pending));
    
    let handles: Vec<_> = (0..3).map(|i| {
        let task = shared_task.clone();
        thread::spawn(move || {
            // 使用fetch_update原子更新状态
            task.fetch_update(Ordering::SeqCst, Ordering::Relaxed, |state| {
                match state {
                    TaskState::Pending => Some(TaskState::Processing),
                    TaskState::Processing => Some(TaskState::Completed),
                    _ => None,
                }
            }).unwrap();
            println!("线程{}更新了任务状态", i);
        })
    }).collect();
    
    for handle in handles {
        handle.join().unwrap();
    }
    
    println!("最终任务状态: {:?}", shared_task.load(Ordering::SeqCst));
}

这个完整示例展示了portable_atomic_enum库的主要功能:

  1. 定义原子枚举类型
  2. 基本原子操作(load/store/swap)
  3. 比较并交换(CAS)操作
  4. 多线程环境下的安全状态更新
  5. 使用fetch_update进行复杂状态转换

输出结果会显示任务状态在不同线程间的原子转换过程。

回到顶部