Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do the thread local variables in the Rust standard library work?

How do the thread local variables in the Rust standard library work? I looked at the code, but got lost in indirection. It seems that there are different configurations for thread local storage, an OS dependent mode and a fast mode. Which one is the default, and how do I choose which one to use? In particular, what are the implications of using thread local storage in a crate for the user of the crate?

Using thread local storage is simple enough, and the generated assembly looks really efficient, but I can not use the feature in a library without fully understanding the implications.

I've also asked:

  • How many bytes will a thread local variable in Rust use?
like image 998
Rüdiger Klaehn Avatar asked Nov 19 '19 20:11

Rüdiger Klaehn


People also ask

How does thread local storage work?

With thread local storage (TLS), you can provide unique data for each thread that the process can access using a global index. One thread allocates the index, which can be used by the other threads to retrieve the unique data associated with the index.

What is Rust thread_ local?

This library provides the ThreadLocal type which allow a separate copy of an object to be used for each thread. This allows for per-object thread-local storage, unlike the standard library's thread_local! macro which only allows static thread-local storage. Documentation.

What is thread local memory?

Thread Local Storage (TLS) is the method by which each thread in a given multithreaded process can allocate locations in which to store thread-specific data. Dynamically bound (run-time) thread-specific data is supported by way of the TLS API (TlsAlloc).


1 Answers

The different configurations you see are related to #[thread_local], a feature that is intended to replace the thread_local! macro to make the user code more straightforward, e.g.:

#![feature(thread_local)]

#[thread_local]
pub static mut VAR: u64 = 42;

However, at the moment of writing, this feature is not fully implemented yet (you can find the tracking issue here). It is used internally in the compiler code though, and that is the magic you see in the actual 'fast' implementation in std::thread::LocalKey:

#[thread_local]
#[cfg(all(
    target_thread_local,
    not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
))]
static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
    $crate::thread::__FastLocalKeyInner::new();

Notice the #[thread_local] attribute at the top. It is then translated down to LLVM IR, so the actual implementation of TLS (thread-local storage) is carried by LLVM and implements the ELF TLS models. This is the default configuration.

how do I choose which one to use?

You'll need to compile your own rustc version with the target_thread_local feature omitted. In that case, the os variant of std::thread::LocalKey will be used, and then, depending on a platform, it can use pthreads (Unix), or Windows API, or something else.

WebAssembly is a special case: as it doesn't support threads, TLS will be translated down to simple static variables.

like image 78
NikitaBaksalyar Avatar answered Oct 07 '22 03:10

NikitaBaksalyar