ThreadLocal
Per-thread values: ThreadLocal<T> gives every thread its own copy of a
variable.
Source: runtime/async/thread_local.pep
ThreadLocal
[Shared] struct ThreadLocal<T>
A variable with a separate value on every thread, like C++
thread_local or Rust’s thread_local!.
Each thread that calls set stores its own value. When a thread exits, its
value is released.
For a thread-safe T (a number, a [Shared] struct), get returns the
calling thread’s value (the default of T, zero or null, until that thread
sets one). For any other T, such as a String, the value is reached
through a with block, with (var value = local.enter()) { ... }, and
get is a compile error; set then takes a new value (a constructor call,
a string literal, copy(x)). Inside the block the value is kept apart
from the rest of the program, as for a Mutex.
A ThreadLocal is [Shared], so one object can be used from every
thread; it is usually a module-scope variable. T does not have to be
thread-safe, because each value stays on the thread that stored it.
Destroying a ThreadLocal releases the calling thread’s value; values
that other threads still hold are released when those threads exit.
A thread’s values are released when it exits if Thread.spawn started
it (the async runtime’s workers too). The main thread’s are released
only by clear(), and a thread started by C code leaks the values it did
not clear.
Type parameters
T— the type of the per-thread value
Example
import async;
const calls = async.ThreadLocal<int>();
count_call() {
calls.set(calls.get() + 1);
}
main(): int {
count_call();
count_call();
assert(calls.get() == 2, "two calls on this thread");
return 0;
}
Constructor
ThreadLocal()
construct()
Creates a thread-local variable. No thread has a value yet.
Methods
get
get(): T
Returns the calling thread’s value.
For a struct T the caller gets its own reference. Only for a
thread-safe T: for any other T, use with (var value = local.enter()).
Returns
- the value this thread last stored, or the default of
T(zero or null) if it has not stored one
set
set([Move] value: T)
Stores value as the calling thread’s value, replacing (and, for a
struct T, releasing) the one it held. Other threads’ values are not
affected.
For a T that is not thread-safe, value must be a new value (a
constructor call, a string literal, copy(x)), which the compiler
checks.
Parameters
value— the new value for this thread
enter
enter(): ThreadLocalGuard<T>
Returns the guard that a with block enters to reach the calling
thread’s value: with (var value = local.enter()) { ... }. The body
runs with the value bound; the else block runs when this thread has
no value (for a struct T).
Returns
- the guard; its
enter()returns this thread’s value
Example
const names = async.ThreadLocal<Array<String>>();
remember(String name) {
if (!names.is_set()) {
names.set(Array<String>());
}
with (var list = names.enter()) {
list.append(name.copy());
}
}
is_set
is_set(): bool
Reports whether the calling thread has stored a value since it started
or last called clear().
Returns
- true if this thread has a value
clear
clear()
Removes the calling thread’s value, releasing it for a struct T.
get() returns the default of T afterwards.
ThreadLocalGuard
[Isolated] struct ThreadLocalGuard<T>
The access to a thread’s ThreadLocal<T> value that a with block holds:
enter() returns the value. Get one from ThreadLocal.enter().
A guard is [Isolated]: it can only be the scope of a with header, and
the compiler checks the block with the confinement rule (see Mutex).
Type parameters
T— the type of the per-thread value
Constructor
ThreadLocalGuard()
construct(local: ThreadLocal<T>)
Creates the guard for the calling thread’s value of local; the same
as local.enter().
Parameters
local— the thread-local variable
Methods
enter
enter(): T
Returns the calling thread’s value, for the with header to bind.
Returns
- this thread’s value, or the default of
T(null for a struct) when it has none
exit
exit()
Does nothing: the value stays with the thread.