|
1 | 1 | # dropping-thread-local |
2 | | -A rewrite of the [`thread_local` crate](https://crates.io/crates/thread_local) that supports destructors. |
| 2 | +<!-- cargo-rdme start --> |
| 3 | + |
| 4 | +Dynamically allocated thread locals that properly run destructors when a thread is destroyed. |
| 5 | + |
| 6 | +This is in contrast to the [`thread_local`] crate, which has similar functionality, |
| 7 | +but only runs destructors when the `ThreadLocal` object is dropped. |
| 8 | +This crate guarantees that one thread will never see the thread-local data of another, |
| 9 | +which can happen in the `thread_local` crate due to internal storage reuse. |
| 10 | + |
| 11 | +This crate attempts to implement "true" thread locals, |
| 12 | +mirroring [`std::thread_local!`] as closely as possible. |
| 13 | +I would say the `thread_local` crate is good for functionality like reusing allocations |
| 14 | +or for having local caches that can be sensibly reused once a thread dies. |
| 15 | + |
| 16 | +This crate will attempt to run destructors as promptly as possible, |
| 17 | +but taking snapshots may interfere with this (see below). |
| 18 | +Panics in thread destructors will cause aborts, just like they do with [`std::thread_local!`]. |
| 19 | + |
| 20 | +Right now, this crate has no unsafe code. |
| 21 | +This may change if it can bring a significant performance improvement. |
| 22 | + |
| 23 | +## Snapshots |
| 24 | +The most complicated feature of this library is snapshots. |
| 25 | +It allows anyone who has access to a [`DroppingThreadLocal`] to iterate over all currently live |
| 26 | +values using the [`DroppingThreadLocal::snapshot_iter`] method. |
| 27 | + |
| 28 | +This will return a snapshot of the live values at the time the method is called, |
| 29 | +although if a thread dies during iteration, it may not show up. |
| 30 | +See the method documentation for more details. |
| 31 | + |
| 32 | +## Performance |
| 33 | +I expect the current implementation to be noticeably slower than either |
| 34 | +[`std::thread_local!`] or the [`thread_local`] crate. |
| 35 | +I have not done any benchmarks to compare the performance. |
| 36 | + |
| 37 | +### Locking |
| 38 | +The implementation needs to acquire a global lock to initialize/deinitialize threads and create new locals. |
| 39 | +Accessing thread-local data is also protected by a per-thread lock. |
| 40 | +This lock should be uncontended, and [`parking_lot::Mutex`] should make this relatively fast. |
| 41 | +I have been careful to make sure that locks are not held while user code is being executed. |
| 42 | +This includes releasing locks before any destructors are executed. |
| 43 | + |
| 44 | +## Limitations |
| 45 | +The type that is stored must be `Send + Sync + 'static`. |
| 46 | +The `Send` bound is necessary because the [`DroppingThreadLocal`] may be dropped from any thread. |
| 47 | +The `Sync` bound is necessary to support snapshots, |
| 48 | +and the `'static` bound is due to internal implementation chooses (use of safe code). |
| 49 | + |
| 50 | +A Mutex can be used to work around the `Sync` limitation. |
| 51 | +(I recommend [`parking_lot::Mutex`], which is optimized for uncontented locks) |
| 52 | +You can attempt to use the [`fragile`] crate to work around the `Send` limitation, |
| 53 | +but this will cause panics if the value is dropped from another thead. |
| 54 | +Some ways a value can be dropped from another thread if a snapshot keeps the value alive, |
| 55 | +or if the [`DroppingThreadLocal`] itself is dropped. |
| 56 | + |
| 57 | +[`thread_local`]: https://docs.rs/thread_local/1.1/thread_local/ |
| 58 | +[`fragile`]: https://docs.rs/fragile/2/fragile/ |
| 59 | + |
| 60 | +<!-- cargo-rdme end --> |
| 61 | + |
| 62 | +<!-- cargo inline doc references --> |
| 63 | +[`std::thread_local!`]: https://doc.rust-lang.org/std/macro.thread_local.html |
| 64 | +[`parking_lot::Mutex`]: https://docs.rs/parking_lot/latest/parking_lot/type.Mutex.html |
| 65 | +[`DroppingThreadLocal`]: https://docs.rs/dropping-thread-local/latest/dropping-thread-local/struct.DroppingThreadLocal.html |
| 66 | +[`DroppingThreadLocal::snapshot_iter`]: https://docs.rs/dropping-thread-local/latest/dropping-thread-local/struct.DroppingThreadLocal.html#method.snapshot_iter |
| 67 | + |
0 commit comments