Names matching ^tss_[a-z]
might be added to <threads.h>.
An object with thread storage
duration is really a set of objects, each one
accessible to a different thread, but all identified as the same object.
Such objects are also known as thread locals, and
are declared with the keyword
_Thread_local or the macro
thread_local, which expands to
_Thread_local. We'll call the actual
objects ‘instances’, and each one is owned by the thread that
accesses it. For example:
counter allows any thread to keep
track of how many times it has invoked do_something. There is no need for any mutex to access the
variable safely, as each thread can only access its own
instance.
An instance is created the first time the owning thread
accesses the
thread_local object. It is initialized
with the value provided in the declaration, if present.
Otherwise, it takes on the appropriate null value for the
type.
Another mechanism exists, called thread-specific
storage, which permits destructors to be associated
with thread-local data, so that the instances of the data
will be properly discarded when a thread terminates. The type
tss_t identifies an item of thread-specific
storage, whose instances have the type void
*.
tss_create
creates a thread-specific object. On success, it assigns the
identifier for the object to *kp, and
returns thrd_success. Otherwise, it returns
thrd_error.
The initial value for each instance of the object is
NULL.
dtor identifies a
destructor. The current value v of an instance will be passed to (*dtor)(v) when the owning thread is terminating,
if dtor is not 0, and v is not
NULL. The current value is
reset to NULL before calling the
destructor. After the destructor returns, the current value
is checked again to see if it is still NULL. If not, the destruction
process repeats. This occurs upto
TSS_DTOR_ITERATIONS times. The owning
thread calls the destructor.
tss_get
gets the current value of the instance of object k for the current thread. Note that it returns
NULL on failure, but it will
also return NULL if that happens to be the
current value, and there is no way to distinguish between
these two events.
tss_set
sets the current value to v,
[Does it call the destructor then for the
old value?] and returns thrd_success, or thrd_error on failure. Unless
you're sure that the old value is not NULL, you should first call
tss_get
to obtain it and deallocate it, and then call tss_set
with the new value.
tss_delete
releases resources allocated to the thread-specific object
k. This does not invoke the destructor
on any instance, so it should not be called unless all
instances are known to be NULL or otherwise require
no destruction.
Example
[:Hmm, don't
think I've actually tried this code
out!]
Given a type foo_t acting as a
handle for some sort of context, a function foo_createctxt to create a context, and
foo_destroyctxt to destroy a
context, define a new function foo_getctxt to create a context for the
calling thread on demand, or return a previously created
one. Each context is destroyed when its thread
terminates.