Doc. No.: | WG14/N1329 |
---|---|
Date: | 2008-08-06 |
Reply to: | Clark Nelson |
Phone: | +1-503-712-8433 |
Email: | clark.nelson@intel.com |
At its 2008-06 meeting in Sophia Antipolis, WG21 accepted N2659 as a specification of thread-local storage. The motivation for this feature is clear and compelling; I am personally unaware of any hosted implementation of C that doesn't already provide it, using some spelling or other.
The changes to the standard necessary to add this feature to C are fairly limited and straightforward. (The changes to C++ are more extensive mainly because they address dynamic initialization and destruction. It should be noted that allowing dynamic initialization and destruction for thread-local objects in C++ is a fairly significant extension of existing practice.) I have retained the keyword spelling and terminology adopted into the C++ standard for consistency, not because I necessarily believe them to be optimal.
It is perhaps worth pointing out that this specification requires that a thread-specific instance of a thread-local variable has a distinct (non-constant) address, and that it is possible for a thread to indirectly access a thread-specific instance corresponding to a different thread.
Change p1:
An object has a storage duration that determines its lifetime. There are three four storage durations: static, thread, automatic, and allocated. Allocated storage is described in 7.20.3.
Change p3:
An object whose identifier is declared without the storage-class specifier
thread_local
, and either with external or internal linkage, or with the storage-class specifierstatic
, has static storage duration. Its lifetime is the entire execution of the program and its stored value is initialized only once, prior to program startup.
Insert new paragraph after p3:
An object whose identifier is declared with the storage-class specifier
thread_local
has thread storage duration. Its lifetime is the entire execution of the thread for which it is created, and its stored value is initialized when the thread is started. There is a distinct object per thread, and use of the declared name in an expression refers to the object associated with the thread evaluating the expression.
To p1, add thread_local
.
Change p1:
- storage-class-specifier:
typedef
extern
static
thread_local
auto
register
Change p2:
At most, one storage-class specifier may be given in the declaration specifiers in a declaration, except that
thread_local
may appear withstatic
orextern
.102)
NOTE: Allowing thread_local
with either static
or
extern
is the only obvious way to control the linkage of a thread-local
object declared at file-scope.
Add a new Constraints paragraph following p2:
In the declaration of a block-scope object, if the declaration specifiers include
thread_local
, they shall also include eitherstatic
orextern
. Ifthread_local
appears in any declaration of an object, it shall be present in every declaration of that object.
NOTE: The current words in the C++ standard prohibit block-scope extern
declarations of thread-local objects, but that was an oversight.
Change p3:
An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static or thread storage duration, and shall not contain a reference to an identifier with internal linkage.
Change p2:
An ordinary identifier (as defined in 6.2.3) that has a variably modified type shall have either block scope and no linkage or function prototype scope. If an identifier is declared to be an object with static or thread storage duration, it shall not have a variable length array type.
Change p10:
EXAMPLE 4 All declarations of variably modified (VM) types have to be at either block scope or function prototype scope. Array objects declared with the
thread_local
,static
orextern
storage-class specifier cannot have a variable length array (VLA) type. However, an object declared with thestatic
storage-class specifier can have a VM type (that is, a pointer to a VLA type). Finally, all identifiers declared with a VM type have to be ordinary identifiers and cannot, therefore, be members of structures or unions.
Change p4:
All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.
Change p10:
If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static or thread storage duration is not initialized explicitly, then:
- if it has pointer type, it is initialized to a null pointer;
- if it has arithmetic type, it is initialized to (positive or unsigned) zero;
- if it is an aggregate, every member is initialized (recursively) according to these rules;
- if it is a union, the first named member is initialized (recursively) according to these rules.
Change p4:
The functions in the standard library are not guaranteed to be reentrant and may modify objects with static or thread storage duration.164)
signal
functionChange p5:
If the signal occurs other than as the result of calling the
abort
orraise
function, the behavior is undefined if the signal handler refers to any object with static or thread storage duration other than by assigning a value to an object declared asvolatile sig_atomic_t
, or the signal handler calls any function in the standard library other than theabort
function, the_Exit
function, or thesignal
function with the first argument equal to the signal number corresponding to the signal that caused the invocation of the handler. Furthermore, if such a call to thesignal
function results in aSIG_ERR
return, the value oferrno
is indeterminate.220)
Change p1:
An arithmetic constant expression of floating type, other than one in an initializer for an object that has static or thread storage duration, is evaluated (as if) during execution; thus, it is affected by any operative floating-point control modes and raises floating-point exceptions as required by IEC 60559 (provided the state for the
FENV_ACCESS
pragma is “on”).315)
Change p1:
All computation for automatic initialization is done (as if) at execution time; thus, it is affected by any operative modes and raises floating-point exceptions as required by IEC 60559 (provided the state for the
FENV_ACCESS
pragma is “on”). All computation for initialization of objects that have static or thread storage duration is done (as if) at translation time.