Struct LocalKey
pub struct LocalKey<T: 'static> { pub(in ::thread::local) inner: fn(Option<&mut Option<T>>) -> *const T }
A thread local storage (TLS) key which owns its contents.
This key uses the fastest implementation available on the target platform.
It is instantiated with the thread_local! macro and the
primary method is the with method, though there are helpers to make
working with Cell types easier.
The with method yields a reference to the contained value which cannot
outlive the current thread or escape the given closure.
Initialization and Destruction
Initialization is dynamically performed on the first call to a setter (e.g.
with) within a thread, and values that implement Drop get
destructed when a thread exits. Some platform-specific caveats apply, which
are explained below.
Note that, should the destructor panic, the whole process will be aborted.
On platforms where initialization requires memory allocation, this is
performed directly through System, allowing the global allocator
to make use of thread local storage.
A LocalKey's initializer cannot recursively depend on itself. Using a
LocalKey in this way may cause panics, aborts, or infinite recursion on
the first call to with.
Single-thread Synchronization
Though there is no potential race with other threads, it is still possible to
obtain multiple references to the thread-local data in different places on
the call stack. For this reason, only shared (&T) references may be obtained.
To allow obtaining an exclusive mutable reference (&mut T), typically a
Cell or RefCell is used (see the std::cell for more information
on how exactly this works). To make this easier there are specialized
implementations for LocalKey<Cell<T>> and LocalKey<RefCell<T>>.
Examples
use Cell;
use thread;
// explicit `const {}` block enables more efficient initialization
thread_local!;
assert_eq!;
FOO.set;
// each thread starts out with the initial value of 1
let t = spawn;
// wait for the thread to complete and bail out on panic
t.join.unwrap;
// we retain our original value of 2 despite the child thread
assert_eq!;
Platform-specific behavior
Note that a "best effort" is made to ensure that destructors for types stored in thread local storage are run, but not all platforms can guarantee that destructors will be run for all types in thread local storage. For example, there are a number of known caveats where destructors are not run:
-
On Unix systems when pthread-based TLS is being used, destructors will not be run for TLS values on the main thread when it exits. Note that the application will exit immediately after the main thread exits as well.
-
On all platforms it's possible for TLS to re-initialize other TLS slots during destruction. Some platforms ensure that this cannot happen infinitely by preventing re-initialization of any slot that has been destroyed, but not all platforms have this guard. Those platforms that do not guard typically have a synthetic limit after which point no more destructors are run.
-
When the process exits on Windows systems, TLS destructors may only be run on the thread that causes the process to exit. This is because the other threads may be forcibly terminated.
TLS destructors may be leaked if a thread exits while converted into a fiber, or if Rust TLS destructor support is first needed while running in a fiber.
If a process loads a Rust
cdylib, it must not cause the Rust TLS destructor support to be initialized for the first time during process shutdown.When dynamically unloading a Rust
cdylib, pending TLS destructors may run during the unload or may be leaked.
Fields
inner: fn(Option<&mut Option<T>>) -> *const T
Implementations
impl<T: 'static> LocalKey<Cell<T>>
fn set(&'static self, value: T)Sets or initializes the contained value.
Unlike the other methods, this will not run the lazy initializer of the thread local. Instead, it will be directly initialized with the given value if it wasn't initialized yet.
Panics
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
Examples
use Cell; thread_local! // Calling X.get() here would result in a panic. X.set; // But X.set() is fine, as it skips the initializer above. assert_eq!;fn get(&'static self) -> T where T: Copy,Returns a copy of the contained value.
This will lazily initialize the value if this thread has not referenced this key yet.
Panics
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
Examples
use Cell; thread_local! assert_eq!;fn take(&'static self) -> T where T: Default,Takes the contained value, leaving
Default::default()in its place.This will lazily initialize the value if this thread has not referenced this key yet.
Panics
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
Examples
use Cell; thread_local! assert_eq!; assert_eq!;fn replace(&'static self, value: T) -> TReplaces the contained value, returning the old value.
This will lazily initialize the value if this thread has not referenced this key yet.
Panics
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
Examples
use Cell; thread_local! assert_eq!; assert_eq!;fn update(&'static self, f: impl FnOnce(T) -> T) where T: Copy,Updates the contained value using a function.
This will lazily initialize the value if this thread has not referenced this key yet.
Panics
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
Examples
use Cell; thread_local! X.update; assert_eq!;
impl<T: 'static> LocalKey<RefCell<T>>
fn with_borrow<F, R>(&'static self, f: F) -> R where F: FnOnce(&T) -> R,Acquires a reference to the contained value.
This will lazily initialize the value if this thread has not referenced this key yet.
Panics
Panics if the value is currently mutably borrowed.
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
Examples
use RefCell; thread_local! X.with_borrow;fn with_borrow_mut<F, R>(&'static self, f: F) -> R where F: FnOnce(&mut T) -> R,Acquires a mutable reference to the contained value.
This will lazily initialize the value if this thread has not referenced this key yet.
Panics
Panics if the value is currently borrowed.
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
Examples
use RefCell; thread_local! X.with_borrow_mut; X.with_borrow;fn set(&'static self, value: T)Sets or initializes the contained value.
Unlike the other methods, this will not run the lazy initializer of the thread local. Instead, it will be directly initialized with the given value if it wasn't initialized yet.
Panics
Panics if the value is currently borrowed.
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
Examples
use RefCell; thread_local! // Calling X.with() here would result in a panic. X.set; // But X.set() is fine, as it skips the initializer above. X.with_borrow;fn take(&'static self) -> T where T: Default,Takes the contained value, leaving
Default::default()in its place.This will lazily initialize the value if this thread has not referenced this key yet.
Panics
Panics if the value is currently borrowed.
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
Examples
use RefCell; thread_local! X.with_borrow_mut; let a = X.take; assert_eq!; X.with_borrow;fn replace(&'static self, value: T) -> TReplaces the contained value, returning the old value.
Panics
Panics if the value is currently borrowed.
Panics if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
Examples
use RefCell; thread_local! let prev = X.replace; assert!; X.with_borrow;
impl<T: 'static> LocalKey<T>
const unsafe fn new(inner: fn(Option<&mut Option<T>>) -> *const T) -> LocalKey<T>fn with<F, R>(&'static self, f: F) -> R where F: FnOnce(&T) -> R,Acquires a reference to the value in this TLS key.
This will lazily initialize the value if this thread has not referenced this key yet.
Panics
This function will
panic!()if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.Examples
thread_local! assert_eq!;fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError> where F: FnOnce(&T) -> R,Acquires a reference to the value in this TLS key.
This will lazily initialize the value if this thread has not referenced this key yet. If the key has been destroyed (which may happen if this is called in a destructor), this function may return an
AccessError.Panics
This function will still
panic!()if the key is uninitialized and the key's initializer panics.Examples
thread_local! assert_eq!;fn initialize_with<F, R>(&'static self, init: T, f: F) -> R where F: FnOnce(Option<T>, &T) -> R,Acquires a reference to the value in this TLS key, initializing it with
initif it wasn't already initialized on this thread.If
initwas used to initialize the thread local variable,Noneis passed as the first argument tof. If it was already initialized,Some(init)is passed tof.Panics
This function will panic if the key currently has its destructor running, and it may panic if the destructor has previously been run for this thread.
Trait Implementations
impl<T: 'static> Debug for LocalKey<T>
fn fmt(&self, f: &mut Formatter<'_>) -> Result
Auto Trait Implementations
impl<T> Freeze for LocalKey<T>
where
fn(Option<&mut Option<T>>) -> *const T: Freeze,
impl<T> RefUnwindSafe for LocalKey<T>
where
fn(Option<&mut Option<T>>) -> *const T: RefUnwindSafe,
impl<T> Send for LocalKey<T>
where
fn(Option<&mut Option<T>>) -> *const T: Send,
impl<T> Sync for LocalKey<T>
where
fn(Option<&mut Option<T>>) -> *const T: Sync,
impl<T> Unpin for LocalKey<T>
where
fn(Option<&mut Option<T>>) -> *const T: Unpin,
impl<T> UnsafeUnpin for LocalKey<T>
where
fn(Option<&mut Option<T>>) -> *const T: UnsafeUnpin,
impl<T> UnwindSafe for LocalKey<T>
where
fn(Option<&mut Option<T>>) -> *const T: UnwindSafe,
Blanket Implementations
impl<T> Any for LocalKey<T>
where
T: 'static + ?Sized,
fn type_id(&self) -> TypeId
impl<T> Borrow<T> for LocalKey<T>
where
T: ?Sized,
fn borrow(&self) -> &T
impl<T> BorrowMut<T> for LocalKey<T>
where
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
impl<T> From<T> for LocalKey<T>
fn from(t: T) -> TReturns the argument unchanged.
impl<T> SizeHint for LocalKey<T>
where
T: ?Sized,
fn lower_bound(&self) -> usizefn upper_bound(&self) -> Option<usize>
impl<T> SizedTypeProperties for LocalKey<T>
impl<T, U> Into<U> for LocalKey<T>
where
U: From<T>,
fn into(self) -> UCalls
U::from(self).That is, this conversion is whatever the implementation of
[From]<T> for Uchooses to do.
impl<T, U> TryFrom<U> for LocalKey<T>
where
U: Into<T>,
type Error = Infallible;fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
impl<T, U> TryInto<U> for LocalKey<T>
where
U: TryFrom<T>,
type Error = <U as TryFrom<T>>::Error;fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>