Rust 实现线程安全的 Lock Free 计数器

完整代码:https://github.com/chiehw/hello_rust/blob/main/crates/counter/src/lib.rs

定义 Trait

Trait 可以看作是一种能力的抽象,和接口有点类似。Trait 还能作为泛型约束条件,作为参数的限制条件。

pub trait AtomicCounter: Send + Sync {
  type PrimitiveType;

  fn get(&self) -> Self::PrimitiveType;	// 获取当前计数器的值。
  fn increase(&self) -> Self::PrimitiveType;	// 自增,并返回上一次的值
  fn add(&self, count: Self::PrimitiveType) -> Self::PrimitiveType;	// 添加一个数,并返回上一次的值
  fn reset(&self) -> Self::PrimitiveType;	// 重置计数器
  fn into_inner(self) -> Self::PrimitiveType;	// 获取内部值
}

简单的测试用例TDD

使用测试驱动开发可以让目标更明确,这里先写个简单的测试案例。

#[cfg(test)]
mod tests {
  use super::*;

  fn test_simple<Counter>(counter: Counter)
  where
    Counter: AtomicCounter<PrimitiveType = usize>,	// 使用 Trait 作为泛型约束条件
  {
    counter.reset();
    assert_eq!(0, counter.add(5));
    assert_eq!(5, counter.increase());
    assert_eq!(6, counter.get())
  }

  #[test]
  fn it_works() {
    test_simple(RelaxedCounter::new(10));
  }
}

亿点细节

直接封装 AtomicUsize

#[derive(Default, Debug)]
pub struct ConsistentCounter(AtomicUsize);

impl ConsistentCounter {
  pub fn new(init_num: usize) -> ConsistentCounter {
    ConsistentCounter(AtomicUsize::new(init_num))
  }
}

impl AtomicCounter for ConsistentCounter {
  type PrimitiveType = usize;

  fn get(&self) -> Self::PrimitiveType {
    self.0.load(Ordering::SeqCst)
  }

  fn increase(&self) -> Self::PrimitiveType {
    self.add(1)
  }

  fn add(&self, count: Self::PrimitiveType) -> Self::PrimitiveType {
    self.0.fetch_add(count, Ordering::SeqCst)
  }

  fn reset(&self) -> Self::PrimitiveType {
    self.0.swap(0, Ordering::SeqCst)
  }

  fn into_inner(self) -> Self::PrimitiveType {
    self.0.into_inner()
  }
}

增加测试用例

使用多线程同时对计数器进行操作,然后判断计数的结果是否正确。更多的测试案例请查看【完整代码】

fn test_increase<Counter>(counter: Arc<Counter>)
  where
    Counter: AtomicCounter<PrimitiveType = usize> + Debug + 'static,
  {
    println!("[+] test_increase: Spawning {} thread, each with {}", NUM_THREADS, NUM_ITERATIONS);
    let mut join_handles = Vec::new();
    // 创建 NUM_THREADS 个线程,同时使用 increase 函数
    for _ in 0..NUM_THREADS {
      let counter_ref = counter.clone();
      join_handles.push(thread::spawn(move || {
        let counter: &Counter = counter_ref.deref();
        for _ in 0..NUM_ITERATIONS {
          counter.increase();
        }
      }));
    }
    // 等待线程完成
    for handle in join_handles {
      handle.join().unwrap();
    }
    let count = Arc::try_unwrap(counter).unwrap().into_inner();
    let excepted_num = NUM_ITERATIONS * NUM_THREADS;
    println!("[+] test_increase: get count {}, excepted num is {}", count, excepted_num);
    // 确定 count 正确
    assert_eq!(count, excepted_num)
  }

参考教程:

  • 谈谈 C++ 中的内存顺序 (Memory Order):https://luyuhuang.tech/2022/06/25/cpp-memory-order.html#happens-before

相关推荐

  1. Rust 实现线安全 Lock Free 计数器

    2024-04-12 05:54:07       36 阅读
  2. JUC练习——线安全计数器

    2024-04-12 05:54:07       24 阅读
  3. 设计一个Rust线安全栈结构 Stack<T>

    2024-04-12 05:54:07       44 阅读
  4. 线安全Map

    2024-04-12 05:54:07       70 阅读
  5. 【多线线安全单例模式

    2024-04-12 05:54:07       26 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-12 05:54:07       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-12 05:54:07       101 阅读
  3. 在Django里面运行非项目文件

    2024-04-12 05:54:07       82 阅读
  4. Python语言-面向对象

    2024-04-12 05:54:07       91 阅读

热门阅读

  1. Linux tftp 环境搭建

    2024-04-12 05:54:07       34 阅读
  2. 动态规划专练( 1049.最后一块石头的重量Ⅱ)

    2024-04-12 05:54:07       39 阅读
  3. 创建自定义 通知栏

    2024-04-12 05:54:07       33 阅读
  4. TCP_NODELAY在延迟敏感的场景下适合设置

    2024-04-12 05:54:07       33 阅读
  5. 一种无OS的MCU实用软件开源框架

    2024-04-12 05:54:07       35 阅读
  6. 大数据之kafka应用

    2024-04-12 05:54:07       37 阅读
  7. (最新)itext7 freemarker动态模板转pdf

    2024-04-12 05:54:07       34 阅读
  8. jodconverter+openOffice word文档pdf转换

    2024-04-12 05:54:07       40 阅读
  9. Spring Cloud启动类上的注解详解

    2024-04-12 05:54:07       34 阅读