为结构的每个实例生成顺序ID

anj*_*ruu 7 rust

我正在写一个系统,我有一个Objects 的集合,每个Object都有一个唯一的整数ID.这是我在C++中如何做到这一点:

class Object {
public:
  Object(): id_(nextId_++) { }

private:
  int id_;
  static int nextId_;
}

int Object::nextId_ = 1;
Run Code Online (Sandbox Code Playgroud)

这显然不是thread_safe,但如果我想要它,我可以创建nextId_一个std::atomic_int,或者在nextId_++表达式周围包装一个互斥.

我怎么做(最好是安全的)Rust呢?没有静态struct成员,全局可变变量也不安全.我总是可以nextId进入new函数,但是这些对象将被分配到很多地方,我宁愿nextId不管这个数字和yon.思考?

blu*_*uss 10

原子变量可以存在于静态中,因此您可以相对直接地使用它(缺点是您具有全局状态).

示例代码:( 游乐场链接)

use std::{
    sync::atomic::{AtomicUsize, Ordering},
    thread,
};

static OBJECT_COUNTER: AtomicUsize = AtomicUsize::new(0);

#[derive(Debug)]
struct Object(usize);

impl Object {
    fn new() -> Self {
        Object(OBJECT_COUNTER.fetch_add(1, Ordering::SeqCst))
    }
}

fn main() {
    let threads = (0..10)
        .map(|_| thread::spawn(|| Object::new()))
        .collect::<Vec<_>>();

    for t in threads {
        println!("{:?}", t.join().unwrap());
    }
}
Run Code Online (Sandbox Code Playgroud)


She*_*ter 7

全球可变变量也不安全

您的C++示例似乎会出现线程安全问题,但我不太了解C++.

但是,只有非同步的全局可变变量才有问题.如果您不关心跨线程问题,可以使用线程本地:

use std::cell::Cell;

#[derive(Debug)]
struct Monster {
    id: usize,
    health: u8,
}

thread_local!(static MONSTER_ID: Cell<usize> = Cell::new(0));

impl Monster {
    fn new(health: u8) -> Monster {
        MONSTER_ID.with(|thread_id| {
            let id = thread_id.get();
            thread_id.set(id + 1);
            Monster { id, health }
        })
    }
}

fn main() {
    let gnome = Monster::new(41);
    let troll = Monster::new(42);

    println!("gnome {:?}", gnome);
    println!("troll {:?}", troll);
}
Run Code Online (Sandbox Code Playgroud)

如果你确实想要使用多线程更好的东西,请查看bluss'的答案,其中显示了如何使用原子变量.