2015-10-04 53 views
1

我正在编写一个系统,其中我有一个Object的集合,并且每个Object都有一个唯一的集成ID。下面是我会怎么做它在C++:为结构的每个实例生成顺序ID

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

private: 
    int id_; 
    static int nextId_; 
} 

int Object::nextId_ = 1; 

这显然不是thread_safe,但如果我希望它是,我可以做nextId_std::atomic_int,或环绕nextId_++表达互斥。

我该怎么做(最好是安全的)锈?没有静态结构成员,全局可变变量也不安全。我总是可以将nextId传递给new函数,但这些对象将分配到多个位置,我不希望将这些数字编号为nextId。思考?

回答

4

也不是全局可变变量安全

你的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(|id| { 
      let id_val = id.get(); 
      id.set(id_val + 1); 
      Monster { id: id_val, health: health } 
     }) 
    } 
} 

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

    println!("gnome {:?}", gnome); 
    println!("troll {:?}", troll); 
} 

如果你想要的东西,多线程工作得更好,检查出lazy_static crate

注意bluss' answer展示了如何使用原子没有 lazy_static,是这种情况好得多。 lazy_static是更广泛的使用,所以在这里我要离开这个例子现在

#[macro_use] 
extern crate lazy_static; 

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

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

lazy_static!{ 
    static ref MONSTER_ID: AtomicUsize = AtomicUsize::new(0); 
} 

impl Monster { 
    fn new(health: u8) -> Monster { 
     let id = MONSTER_ID.fetch_add(1, Ordering::SeqCst); 
     Monster { id: id, health: health } 
    } 
} 

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

    println!("gnome {:?}", gnome); 
    println!("troll {:?}", troll); 
} 
5

原子变量可以住在静力学,这样你就可以比较直接地使用它(的缺点是,你有全局状态)。

示例代码:(playpen link)

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

static OBJECT_COUNTER: AtomicUsize = atomic::ATOMIC_USIZE_INIT; 

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

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

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

    for t in threads { 
     println!("{:?}", t.join().unwrap()); 
    } 
} 
+0

啊,我总是忘了,你可以静态初始化一个原子,干净多了! – Shepmaster

+1

我以为我应该是建设性的,而不是只挑选一次在SO上发表评论。不知道它是否成功。虽然这是例子。 :) – bluss

+0

那么,在这种情况下添加答案总是一个更好的主意。越来越多的人会这样看待它,如果它更好,它最终可以获得高于其他答案的票数。此外,您通过这种方式获得更多积分,并且每个人都喜欢积分! – Shepmaster

相关问题