程序宏是否在一个线程中编译?

时间:2017-12-09 07:47:23

标签: multithreading rust

我已经实现了一个过程宏来生成一个返回数字的方法:

extern crate unique_type_id;
#[macro_use]
extern crate unique_type_id_derive;

#[test]
fn sequential_simple() {
    use unique_type_id::SequentialTypeId;
    #[derive(SequentialTypeId)]
    struct Test1;
    #[derive(SequentialTypeId)]
    struct Test2;

    assert_eq!(Test1::id().0, 0u64);
    assert_eq!(Test2::id().0, 1u64);
}

我有这个实现,但我不知道是否应该将静态ID置于互斥锁之下:

fn inc_id() -> u64 {
    unsafe {
        static mut ID: u64 = 0u64;

        let old_value = ID;
        ID += 1;
        old_value
    }
}

fn sequential_implementor(ast: &syn::DeriveInput) -> quote::Tokens {
    let name = &ast.ident;
    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    let id = inc_id();

    quote! {
        impl #impl_generics unique_type_id::SequentialTypeId for #name #ty_generics #where_clause {
            fn id() -> unique_type_id::TypeId {
                unique_type_id::TypeId(#id)
            }
        }
    }
}

如果程序宏只使用一个线程,则不需要互斥锁,但我不知道这一点。

1 个答案:

答案 0 :(得分:3)

当你在多个文件甚至多个板条箱中使用它时会发生什么?我认为编译器不能保证任何东西,你根本就不应该使用全局状态(它可以为proc_macro调用分叉,运行多个编译器实例,使用线程,......)。

为了使其线程安全(并避免使用unsafe),您可以像这样使用AtomicUsize

fn inc_id() -> usize {
    use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
    static ID: AtomicUsize = ATOMIC_USIZE_INIT;
    ID.fetch_add(1, Ordering::SeqCst)
}