如何在 Rust 结构内创建线程局部变量?

How to create a thread local variable inside of a Rust struct?

我需要一个线程局部变量,最好存储在当前存储我程序的大部分全局状态的结构中。

我看到的第一种方法是使用 thread_local! 宏,但是我想将此线程保留在我的状态结构中。

我能看到实现此目的的第二种方法是在线程和我的线程局部变量的值之间有一个 HashMap<Thread,MyThreadLocalData> 或类似的。然后我会有一个 getter,它使用 thread::current 来查找适当的值。

我要提到的最后一个要求是,并非给定程序中的所有线程都是由 Rust 代码创建的,但是 Rust 代码可能在任何线程上 运行,因此解决方案应该对此具有鲁棒性。

是否有执行此操作的最佳实践方法?也许有一个 threadId 允许我使用简单的 Vec 而不是 HashMap (and/or 避免散列开销)?有图书馆吗?

另一种选择是修改可在多线程上下文中使用的每个函数的参数,以同时采用状态结构和线程局部状态结构,但这对于非 Rust 创建的线程来说并不容易。

在结构中使用线程局部变量可以通过将其放在 impl 块中来完成:

use std::cell::RefCell;

struct Foo;
impl Foo {
    thread_local! {
        // Could add pub to make it public to whatever Foo already is public to.
        static FOO: RefCell<usize> = RefCell::new(0);
    }
}

并且可以使用 Foo::FOO:

访问
Foo::FOO.with(|x| println!("{:?}", x));

Playground
但是请注意,访问它必须使用它前面的 Foo:: 来完成,因为它不是一个字段,而是一个关联的 static.

也可以通过存储对它的引用来完成:

use std::cell::RefCell;
use std::thread::LocalKey;

thread_local! {
    // Note lack of pub
    static FOO: RefCell<usize> = RefCell::new(0);
}
struct Bar {
    // Visibility here changes what can see `foo`.
    foo: &'static LocalKey<RefCell<usize>>,
    // Rest of your data.
}
impl Bar {
    fn constructor() -> Self {
        Self {
            foo: &FOO,
            // Rest of your data.
        }
    }
}

最简单的方法是使用 thread_local crate:

struct Foo {
    thread_counter: ThreadLocal<AtomicU64>,
}

impl Foo {
    fn new() -> Foo {
        Foo {
            thread_counter: ThreadLocal::new(),
        }
    }
}
let foo = Foo::new();
let count = foo
    .thread_counter
    .get_or(|| AtomicU64::new(START_VALUE))
    .fetch_add(1, Ordering::Relaxed);