diff options
| author | León Orell Valerian Liehr <me@fmease.dev> | 2024-01-03 16:08:33 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-03 16:08:33 +0100 |
| commit | a79fccc288adca3006dfa2c4320885c328a53230 (patch) | |
| tree | 0d6dbefe93ad91343cf182f67809875fff0ca297 | |
| parent | fcec407f4a8a310d369f19b43bb6833db6cc5ebd (diff) | |
| parent | 6f49080fa8f5921e7e2062bb358fd1ad79b8d4ba (diff) | |
| download | rust-a79fccc288adca3006dfa2c4320885c328a53230.tar.gz rust-a79fccc288adca3006dfa2c4320885c328a53230.zip | |
Rollup merge of #119534 - tgross35:thread-local-example-updates, r=JohnTitor
Update `thread_local` examples to use `local_key_cell_methods` `local_key_cell_methods` has been stable for a while and provides a much less clunky way to interface with thread-local Additionaly add context to the documentation about why types with interior mutability are needed. r? libs
| -rw-r--r-- | library/std/src/thread/local.rs | 50 |
1 files changed, 32 insertions, 18 deletions
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index def94acd457..9cf37b0e634 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -16,7 +16,8 @@ use crate::fmt; /// /// This key uses the fastest possible implementation available to it for the /// target platform. It is instantiated with the [`thread_local!`] macro and the -/// primary method is the [`with`] method. +/// 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. @@ -25,14 +26,30 @@ use crate::fmt; /// /// # 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. +/// 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 caveats apply, which are explained below. /// /// 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>>`]. +/// +/// [`std::cell`]: `crate::cell` +/// [`LocalKey<Cell<T>>`]: struct.LocalKey.html#impl-LocalKey<Cell<T>> +/// [`LocalKey<RefCell<T>>`]: struct.LocalKey.html#impl-LocalKey<RefCell<T>> +/// +/// /// # Examples /// /// ``` @@ -41,26 +58,20 @@ use crate::fmt; /// /// thread_local!(static FOO: RefCell<u32> = RefCell::new(1)); /// -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 1); -/// *f.borrow_mut() = 2; -/// }); +/// FOO.with_borrow(|v| assert_eq!(*v, 1)); +/// FOO.with_borrow_mut(|v| *v = 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; -/// }); +/// FOO.with_borrow(|v| assert_eq!(*v, 1)); +/// FOO.with_borrow_mut(|v| *v = 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); -/// }); +/// FOO.with_borrow(|v| assert_eq!(*v, 2)); /// ``` /// /// # Platform-specific behavior @@ -137,10 +148,13 @@ impl<T: 'static> fmt::Debug for LocalKey<T> { /// static BAR: RefCell<f32> = RefCell::new(1.0); /// } /// -/// FOO.with(|foo| assert_eq!(*foo.borrow(), 1)); -/// BAR.with(|bar| assert_eq!(*bar.borrow(), 1.0)); +/// FOO.with_borrow(|v| assert_eq!(*v, 1)); +/// BAR.with_borrow(|v| assert_eq!(*v, 1.0)); /// ``` /// +/// Note that only shared references (`&T`) to the inner data may be obtained, so a +/// type such as [`Cell`] or [`RefCell`] is typically used to allow mutating access. +/// /// This macro supports a special `const {}` syntax that can be used /// when the initialization expression can be evaluated as a constant. /// This can enable a more efficient thread local implementation that @@ -155,7 +169,7 @@ impl<T: 'static> fmt::Debug for LocalKey<T> { /// pub static FOO: Cell<u32> = const { Cell::new(1) }; /// } /// -/// FOO.with(|foo| assert_eq!(foo.get(), 1)); +/// assert_eq!(FOO.get(), 1); /// ``` /// /// See [`LocalKey` documentation][`std::thread::LocalKey`] for more |
