Rust原子枚举库atomic_enum的使用:高效线程安全枚举操作与并发控制

cargo version docs.rs version

atomic_enum

一个用于为C风格枚举创建原子包装器的属性。

在内部,生成的包装器使用AtomicUsize来存储值。 原子操作具有与AtomicUsize的等效操作相同的语义。

示例

# use atomic_enum::atomic_enum;
# use std::sync::atomic::Ordering;
#[atomic_enum]
#[derive(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);

此属性不使用或生成任何不安全代码。

该crate可以在#[no_std]环境中使用。

维护说明

此crate是被动维护的。

完整示例代码

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

// 定义一个原子枚举
#[atomic_enum]
#[derive(PartialEq, Debug)]
enum ThreadState {
    Idle = 0,
    Working,
    Finished,
}

fn main() {
    // 创建原子枚举实例
    let state = Arc::new(AtomicThreadState::new(ThreadState::Idle));
    
    // 克隆Arc用于线程
    let state_clone = Arc::clone(&state);
    
    // 创建工作线程
    let handle = thread::spawn(move || {
        // 将状态设置为Working
        state_clone.store(ThreadState::Working, Ordering::SeqCst);
        println!("线程开始工作...");
        
        // 模拟一些工作
        thread::sleep(std::time::Duration::from_secs(2));
        
        // 将状态设置为Finished
        state_clone.store(ThreadState::Finished, Ordering::SeqCst);
        println!("线程完成工作");
    });
    
    // 主线程监控状态变化
    while state.load(Ordering::SeqCst) != ThreadState::Finished {
        let current_state = state.load(Ordering::SeqCst);
        match current_state {
            ThreadState::Idle => println!("主线程检测到状态: Idle"),
            ThreadState::Working => println!("主线程检测到状态: Working"),
            ThreadState::Finished => break,
        }
        thread::sleep(std::time::Duration::from_millis(500));
    }
    
    // 等待工作线程完成
    handle.join().unwrap();
    
    // 最终状态确认
    assert_eq!(state.load(Ordering::SeqCst), ThreadState::Finished);
    println!("所有操作完成,最终状态: {:?}", state.load(Ordering::SeqCst));
}

1 回复

Rust原子枚举库atomic_enum的使用指南

介绍

atomic_enum是一个专门为Rust设计的原子枚举库,它提供了线程安全的枚举操作能力。通过使用原子操作和内存排序保证,该库能够在多线程环境中安全地操作枚举值,避免了传统互斥锁带来的性能开销。

主要特性

  • 线程安全的枚举值读写操作
  • 支持多种内存排序策略
  • 零额外内存开销(与标准枚举大小相同)
  • 无锁并发控制
  • 与标准库原子类型相似的API设计

使用方法

安装

在Cargo.toml中添加依赖:

[dependencies]
atomic_enum = "0.2"

基本使用示例

use atomic_enum::atomic_enum;
use std::sync::atomic::Ordering;

// 定义原子枚举
#[atomic_enum]
#[derive(PartialEq)]
enum State {
    Idle,
    Running,
    Stopped,
}

fn main() {
    // 创建原子枚举实例
    let state = AtomicState::new(State::Idle);
    
    // 存储枚举值
    state.store(State::Running, Ordering::SeqCst);
    
    // 加载当前值
    let current = state.load(Ordering::SeqCst);
    println!("Current state: {:?}", current);
    
    // 比较并交换操作
    let result = state.compare_exchange(
        State::Running,
        State::Stopped,
        Ordering::SeqCst,
        Ordering::Relaxed
    );
    
    match result {
        Ok(_) => println!("状态成功从Running切换到Stopped"),
        Err(actual) => println!("状态切换失败,当前状态为: {:?}", actual),
    }
}

多线程示例

use atomic_enum::atomic_enum;
use std::sync::atomic::Ordering;
use std::thread;
use std::time::Duration;

#[atomic_enum]
#[derive(PartialEq, Debug)]
enum WorkerState {
    Waiting,
    Processing,
    Completed,
    Error,
}

fn main() {
    let state = AtomicWorkerState::new(WorkerState::Waiting);
    
    // 创建工作线程
    let handle = thread::spawn({
        let state = state.clone();
        move || {
            // 模拟工作
            state.store(WorkerState::Processing, Ordering::Release);
            thread::sleep(Duration::from_millis(100));
            
            // 随机选择完成或错误状态
            if rand::random() {
                state.store(WorkerState::Completed, Ordering::Release);
            } else {
                state.store(WorkerState::Error, Ordering::Release);
            }
        }
    });
    
    // 主线程监控状态
    while state.load(Ordering::Acquire) == WorkerState::Processing {
        println!("工作仍在进行中...");
        thread::sleep(Duration::from_millis(20));
    }
    
    let final_state = state.load(Ordering::Acquire);
    println!("最终状态: {:?}", final_state);
    
    handle.join().unwrap();
}

内存排序选项

atomic_enum支持标准的内存排序选项:

  • Ordering::Relaxed - 最弱的内存排序保证
  • Ordering::Acquire - 加载操作的获取语义
  • Ordering::Release - 存储操作的释放语义
  • Ordering::AcqRel - 获取-释放语义
  • Ordering::SeqCst - 顺序一致性(最强保证)

完整示例demo

use atomic_enum::atomic_enum;
use std::sync::atomic::Ordering;
use std::thread;
use std::time::Duration;
use rand::Rng;

// 定义任务状态枚举
#[atomic_enum]
#[derive(PartialEq, Debug, Clone, Copy)]
enum TaskStatus {
    Pending,    // 等待中
    Processing, // 处理中
    Success,    // 成功
    Failed,     // 失败
    Cancelled,  // 已取消
}

fn main() {
    // 创建原子枚举实例,初始状态为Pending
    let status = AtomicTaskStatus::new(TaskStatus::Pending);
    
    println!("任务启动,初始状态: {:?}", status.load(Ordering::SeqCst));

    // 创建多个工作线程
    let mut handles = vec![];
    
    for i in 0..3 {
        let status_clone = status.clone();
        let handle = thread::spawn(move || {
            // 尝试将状态从Pending改为Processing
            let result = status_clone.compare_exchange(
                TaskStatus::Pending,
                TaskStatus::Processing,
                Ordering::SeqCst,
                Ordering::Relaxed
            );
            
            match result {
                Ok(_) => {
                    println!("线程{}成功获取任务", i);
                    
                    // 模拟任务处理时间
                    thread::sleep(Duration::from_millis(50 + i * 20));
                    
                    // 随机决定任务结果
                    let mut rng = rand::thread_rng();
                    let success: bool = rng.gen();
                    
                    if success {
                        status_clone.store(TaskStatus::Success, Ordering::Release);
                        println!("线程{}任务执行成功", i);
                    } else {
                        status_clone.store(TaskStatus::Failed, Ordering::Release);
                        println!("线程{}任务执行失败", i);
                    }
                }
                Err(current) => {
                    println!("线程{}获取任务失败,当前状态: {:?}", i, current);
                }
            }
        });
        
        handles.push(handle);
    }
    
    // 主线程监控任务状态
    let mut previous_status = status.load(Ordering::Acquire);
    println!("监控开始,当前状态: {:?}", previous_status);
    
    while status.load(Ordering::Acquire) == TaskStatus::Pending {
        thread::sleep(Duration::from_millis(10));
    }
    
    let final_status = status.load(Ordering::Acquire);
    println!("任务最终状态: {:?}", final_status);
    
    // 等待所有线程完成
    for handle in handles {
        handle.join().unwrap();
    }
    
    // 演示状态转换
    println!("\n状态转换演示:");
    let demo_status = AtomicTaskStatus::new(TaskStatus::Pending);
    
    // 状态转换序列
    let transitions = [
        (TaskStatus::Pending, TaskStatus::Processing, "开始处理"),
        (TaskStatus::Processing, TaskStatus::Success, "处理成功"),
        (TaskStatus::Success, TaskStatus::Pending, "重置任务"),
    ];
    
    for (from, to, description) in transitions.iter() {
        match demo_status.compare_exchange(
            *from,
            *to,
            Ordering::SeqCst,
            Ordering::Relaxed
        ) {
            Ok(_) => {
                println!("{}: {:?} -> {:?}", description, from, to);
            }
            Err(actual) => {
                println!("状态转换失败,期望: {:?}, 实际: {:?}", from, actual);
            }
        }
        thread::sleep(Duration::from_millis(100));
    }
}

注意事项

  1. 枚举的变体数量不能超过255个
  2. 枚举的底层表示必须能够用单个字节表示
  3. 建议使用默认的Ordering::SeqCst以确保最强的内存排序保证
  4. 在性能关键场景中,可以根据需要选择更宽松的内存排序

atomic_enum库为Rust开发者提供了简单而高效的线程安全枚举操作方案,特别适合状态机和并发控制场景。

回到顶部