pub struct InstancePerThreadSync<T>{ /* private fields */ }Expand description
A wrapper that manages linked instances of T, ensuring that only one
instance of T is created per thread.
Requires T: Send + Sync.
This is similar to the linked::thread_local_arc! macro, with the main difference
being that this type operates entirely at runtime using dynamic storage and does
not require a static variable to be defined.
§Usage
Create an instance of InstancePerThreadSync and provide it the initial instance of a linked
object T. Any instance of T accessed through the same InstancePerThreadSync or a clone
of it will be linked to the same family.
graph TD
subgraph Thread1[Thread 1]
Task1a[Local task] -->|"::acquire()"| Local1a[RefSync]
Task1b[Local task] -->|"::acquire()"| Local1b[RefSync]
Local1a --> SharedOwnership((Shared
ownership))
Local1b --> SharedOwnership
SharedOwnership --> Instance1[Linked object instance]
end
subgraph Thread2[Thread 2]
Task2a[Local task] -->|"::acquire()"| Local2a[RefSync]
Task2b[Local task] -->|"::acquire()"| Local2b[RefSync]
Local2a --> SharedOwnership2((Shared
ownership))
Local2b --> SharedOwnership2
SharedOwnership2 --> Instance2[Linked object instance]
end
Instance1 --> SharedState[Family state]
Instance2 --> SharedState
To access the current thread’s instance of T, you must first obtain a
RefSync<T> by calling .acquire(). Then you can
access the T within by simply dereferencing via the Deref<Target = T> trait.
RefSync<T> is a thread-aligned type, meaning you can move it to a different thread and even
access it across threads but it will still reference the shared instance of T from the
original thread.
§Resource management
A thread-specific instance of T is dropped when the last RefSync aligned to that thread
is dropped, similar to how Arc<T> would behave. If a new RefSync is later obtained,
it is initialized with a new instance of the linked object.
It is important to emphasize that this means if you only acquire temporary RefSync
instances then you will get a new instance of T every time. The performance impact of
this depends on how T works internally but you are recommended to keep RefSync
instances around for reuse when possible.
Implementations§
Source§impl<T> InstancePerThreadSync<T>
impl<T> InstancePerThreadSync<T>
Sourcepub fn new(inner: T) -> Self
pub fn new(inner: T) -> Self
Creates a new InstancePerThreadSync with an existing instance of T.
Any further access of T instances via the InstancePerThreadSync (or its clones)
will return instances of T from the same family.
Sourcepub fn acquire(&self) -> RefSync<T>
pub fn acquire(&self) -> RefSync<T>
Returns a RefSync<T> that can be used to access the current thread’s instance of T.
Creating multiple concurrent RefSync<T> instances from the same InstancePerThreadSync<T>
on the same thread is allowed. Every RefSync<T> instance will reference the same
instance of T per thread.
There are no constraints on the lifetime of the returned RefSync<T>. It is a
thread-aligned type, so you can move it across threads and access it from a different
thread but it will continue to reference the T instance of the original thread.
§Example
use linked::InstancePerThreadSync;
let linked_thing = InstancePerThreadSync::new(Thing::new());
let thing = linked_thing.acquire();
thing.increment();
assert_eq!(thing.local_value(), 1);§Efficiency
Reuse the returned RefSync<T> when possible. Every call to this function has
some overhead, especially if there are no other RefSync<T> instances from the
same family active on the current thread.
§Instance lifecycle
A thread-specific instance of T is dropped when the last RefSync created on that
thread is dropped. If a new RefSync is later obtained, it is initialized
with a new linked instance of T linked to the same family as the
originating InstancePerThreadSync<T>.
use linked::InstancePerThreadSync;
let linked_thing = InstancePerThreadSync::new(Thing::new());
let thing = linked_thing.acquire();
thing.increment();
assert_eq!(thing.local_value(), 1);
drop(thing);
// Dropping the only acquired instance above will have reset the thread-local state.
let thing = linked_thing.acquire();
assert_eq!(thing.local_value(), 0);To minimize the effort spent on re-creating the thread-local state, ensure that you reuse
the RefSync<T> instances as much as possible.