[][src]Struct os_thread_local::ThreadLocal

pub struct ThreadLocal<T> { /* fields omitted */ }

A thread-local storage handle.

In many ways, this struct works similarly to std::thread::LocalKey, but always relies on OS primitives (see module-level documentation).

The with method yields a reference to the contained value which cannot be sent across threads or escape the given closure.

Initialization and Destruction

Initialization is dynamically performed on the first call to with within a thread, and values that implement Drop get destructed when a thread exits. Some caveats apply, which are explained below.

A ThreadLocal's initializer cannot recursively depend on itself, and using a ThreadLocal in this way will cause the initializer to infinitely recurse on the first call to with.

Examples

This is the same as the example in the std::thread::LocalKey documentation, but adjusted to use ThreadLocal instead. To use it in a static context, a lazy initializer, such as once_cell::sync::Lazy or lazy_static! is required.

use std::cell::RefCell;
use std::thread;
use once_cell::sync::Lazy;
use os_thread_local::ThreadLocal;

static FOO: Lazy<ThreadLocal<RefCell<u32>>> =
    Lazy::new(|| ThreadLocal::new(|| RefCell::new(1)));

FOO.with(|f| {
    assert_eq!(*f.borrow(), 1);
    *f.borrow_mut() = 2;
});

// each thread starts out with the initial value of 1
let t = thread::spawn(move || {
    FOO.with(|f| {
        assert_eq!(*f.borrow(), 1);
        *f.borrow_mut() = 3;
    });
});

// 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
FOO.with(|f| {
    assert_eq!(*f.borrow(), 2);
});

A variation of the same with scoped threads and per-object thread-local storage:

use std::cell::RefCell;
use crossbeam_utils::thread::scope;
use os_thread_local::ThreadLocal;

struct Foo {
    data: u32,
    tls: ThreadLocal<RefCell<u32>>,
}

let foo = Foo {
    data: 0,
    tls: ThreadLocal::new(|| RefCell::new(1)),
};

foo.tls.with(|f| {
    assert_eq!(*f.borrow(), 1);
    *f.borrow_mut() = 2;
});

scope(|s| {
    // each thread starts out with the initial value of 1
    let foo2 = &foo;
    let t = s.spawn(move |_| {
        foo2.tls.with(|f| {
            assert_eq!(*f.borrow(), 1);
            *f.borrow_mut() = 3;
        });
    });

    // 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
    foo.tls.with(|f| {
        assert_eq!(*f.borrow(), 2);
    });
}).unwrap();

Platform-specific behavior and caveats

Note that a "best effort" is made to ensure that destructors for types stored in thread-local storage are run, but it is not guaranteed that destructors will be run for all types in thread-local storage.

  • Destructors may not run on the main thread when it exits.
  • Destructors will not run if the corresponding ThreadLocal is dropped in a child thread (this can happen e.g. if the object or binding holding it is moved into a child thread ; or when the ThreadLocal is created in a child thread).
  • Destructors may not run if a ThreadLocal is initialized during the Drop impl of a type held by another ThreadLocal.
  • The order in which destructors may run when using multiple ThreadLocal is not guaranteed.

On Windows, ThreadLocal provides per-thread storage as long as fibers are unused. When fibers are used, it provides per-fiber storage, which is similar but more fine-grained.

Methods

impl<T> ThreadLocal<T>[src]

pub fn new(f: fn() -> T) -> Self[src]

Creates a new thread-local storage handle.

The provided function is used to initialize the value on the first use in each thread.

use os_thread_local::ThreadLocal;

let tls = ThreadLocal::new(|| 42);

pub fn with<R, F: FnOnce(&T) -> R>(&self, f: F) -> R[src]

Acquires a reference to the value in this thread-local storage.

This will lazily initialize the value if this thread has not accessed it yet.

use os_thread_local::ThreadLocal;
use std::cell::Cell;

let tls = ThreadLocal::new(|| Cell::new(42));
tls.with(|v| v.set(21));

Panics

This function will panic!() if the handle currently has its destructor running, and it may panic if the destructor has previously been run for this thread. This function can also panic!() if the storage is uninitialized and there is not enough available memory to allocate a new thread local storage for the current thread, or if the OS primitives fail.

pub fn try_with<R, F: FnOnce(&T) -> R>(&self, f: F) -> Result<R, AccessError>[src]

Acquires a reference to the value in this thread-local storage.

This will lazily initialize the value if this thread has not accessed it yet. If the storage has been destroyed, this function will return an AccessError.

use os_thread_local::ThreadLocal;
use std::cell::Cell;

let tls = ThreadLocal::new(|| Cell::new(42));
tls.try_with(|v| v.set(21)).expect("storage destroyed");

Panics

This function will panic!() if the storage is uninitialized and the initializer given to ThreadLocal::new panics. This function can also panic!() if the storage is uninitialized and there is not enough available memory to allocate a new thread local storage for the current thread, or if the OS primitives fail.

Trait Implementations

impl<T> Debug for ThreadLocal<T>[src]

impl<T: Default> Default for ThreadLocal<T>[src]

impl<T> Drop for ThreadLocal<T>[src]

Auto Trait Implementations

impl<T> RefUnwindSafe for ThreadLocal<T>

impl<T> Send for ThreadLocal<T>

impl<T> Sync for ThreadLocal<T>

impl<T> Unpin for ThreadLocal<T>

impl<T> UnwindSafe for ThreadLocal<T>

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.