Initial release. â¨
It is impossible to set the name, stack size, stack address + size, (scheduler) priority, processor affinity, and more of a thread in standard C or C++, despite this being both widely available and critical necessities in C and C++ programs. After Bruce Dawson pinged a few C++ standards committee members in circa 2019/2020 asking about thread names, C++ -- particularly, Corentin Jabot -- embarked on an adventure to provide such attributes to their version of C11âs threads, std :: thread
. The effort was marred by platform incompatibilities, specific wording nits, and -- most glaringly -- ABI issues and API wars, resulting in no less than three (3) papers:
They take many approaches to the problem, trying to offer a varying level of ease of use alongside high type safety. The most mature of the papers -- P2019 -- has reached its eighth revision after first being published on March 2nd, 2020 and has not seen success. In that time:
Programming Languages and their standard libraries such as Swift, Java, C#, Haskell, C#, Rust, D, Perl, and many other languages either already supported or support using threads with an explicit stack size parameter and names;
For C and C++, augmentation/replacement standard libraries like Qt, Boost, POCO, Chromium, Bloomberg Basic Development Environment, Intel TBB, Folly, TensorFlow, KallistaOS (Dreamcast OS), tinycthread, and many replace C++11 and C11 threads with their own abstraction in order to do threading.
Importantly, in the case of C11 and C++11 threads, many of them need to rewrite the entire set of thread primitives because of (a) poor support for < threads . h >
until very recently (as of writing: only Apple does not support C11 < threads . h >
; MSVC runtime, OpenBSD, FreeBSD, NetBSD, glibc, musl-libc, Bionic (Android), and more all support < threads . h >
); and, (b) many platforms do not support changing stack sizes, names, and more after thread creation. Therefore, an API cannot simply add set_threadname
or get_threadname
, or similar stack size parameters, with a thread handle parameter as shown by the POSIX Threads implementations. In fact, many implementations have wildly different getting and setting properties and most -- including Windows Threads -- mostly require you to set that information on thread creation, not after-the-fact. A table -- from P2019 -- is reproduced here:
pthread_setname_np
0 pthread_getname_np
QNX pthread_setname_np
pthread_getname_np
NetBSD pthread_setname_np
pthread_getname_np
Win32 SetThreadDescription
1 GetThreadDescription
1 Darwin pthread_setname_np
2 pthread_getname_np
Fuchsia zx_thread_create
Android JavaVMAttachArgs
3 FreeBSD pthread_setname_np
OpenBSD pthread_setname_np
RTEMS 4 pthread_setname_np
pthread_getname_np
FreeRTOS xTaskCreate
pcTaskGetName
VxWorks taskSpawn
eCos cyg_thread_create
Plan 9 threadsetname
5 threadsetname
5 Haiku spawn_thread
rename_thread
get_thread_info
Keil RTX osThreadNew
osThreadGetName
WebAssembly 0
- GLIBC 2.12+, MUSL
- Since Windows 10 1607 - In older versions, a name can be set only when a debugger is attached, by throwing an exception from the calling thread. See [https://stackoverflow.com/a/59490438/877556](Windows Documentation) and
this article by Bruce Dawson.
- Can only be called from the new thread.
- See
https://stackoverflow.com/a/59490438/877556.
- Since 2017.
- Can only be called from the new thread.
Similarly, a lot of APIs suffer from ABI issues; pthread_attr_t
is meant to be ABI-resistant and an opaque type, but implementation still have to contend with issues improving or widening the amount of information it can store without breaking things. C++ std :: thread
âs and P2019, in its attempts to be ABI-resistant, have met a ton of pushback from all kinds of people trying to simplify or reduce the API space and avoid the templated constructors, desperate for a simpler interface and -- in some cases -- ignoring ABI issues with structures similar in purpose to pthread_attr_t
. This has been a consistent theme even among early papers that simply just tried to standardize existing practice without addressing their deficiencies, such as C++'s even earlier papers [P0320] and [N2178].
For C11 threads, these same concerns were voiced during the 2019 Ithaca discussion of Kamil Ryatorwskiâs paper [N2419].
It is clear that this area has strong vendor concerns around extensibility, and even strong constraints around the ability to do this both before thread startup and during thread running.
This paper provides an ABI that is standards-expandable, vendor-extensible, and resistant to Application Binary Interface (ABI) lock-in. It allows vendors to provide more direct ways to adding parameters without compromising current implementations and their structures.
3. DesignThe design is based off an existing API that has proved successful in not replacing but supplementing existing implementations without causing undue burden or breaking the ABIs of existing interfaces. It has been shown to:
set name (in UTF-8/16/32, Execution, Wide Execution, and "direct" forms);
set detached state (to have a thread start in a detached state, (critical for MSVC));
set the stack size (taken as a parameter during startup for MSVC and for POSIX threads);
and, set the stack buffer (a pointer plus size, usable for POSIX threads but not necessarily for MSVC itself).
The API relies on 2 core language features to work:
the pointer to the first member of a structure is identical to the pointer of the structure itself;
and, casting from that first member to a pointer based on the value of that first member is well-defined behavior.
In particular, there is a thrd_attr_kind
enumeration type that is the first member of a structure. It is a tag that tells the implementation what to cast a pointer of that type to, in order to interpret the full structure. It is also the first member of every thread attribute structure, which means it has the same address as the structure itself. This allows an array of thrd_attr_kind
pointers to be passed to thrd_create_attrs
that can be used as a standard and well-defined type-punning point and a sort of "tag" to determine which structure to cast to internally. The full enumeration and API looks as such:
#include <threads.h> #include <stdint.h> typedef enum thrd_attr_kind : int_least32_t { thrd_attr_kind_native_name = 0, thrd_attr_kind_native_name_sized = 1, thrd_attr_kind_mcname = 2, thrd_attr_kind_mcname_sized = 3, thrd_attr_kind_mwcname = 4, thrd_attr_kind_mwcname_sized = 5, thrd_attr_kind_c8name = 6, thrd_attr_kind_c8name_sized = 7, thrd_attr_kind_c16name = 8, thrd_attr_kind_c16name_sized = 9, thrd_attr_kind_c32name = 10, thrd_attr_kind_c32name_sized = 11, thrd_attr_kind_stack_size = 32, thrd_attr_kind_detached = 256, thrd_attr_kind_implementation_defined = 0xFFFF, } thrd_attr_kind; typedef struct thrd_attr_native_name { thrd_attr_kind kind; const void* name; } thrd_attr_native_name; typedef struct thrd_attr_native_name_sized { thrd_attr_kind kind; size_t size; const void* name; } thrd_attr_native_name_sized; typedef struct thrd_attr_mcname { thrd_attr_kind kind; const char* name; } thrd_attr_mcname; typedef struct thrd_attr_mcname_sized { thrd_attr_kind kind; size_t size; const char* name; } thrd_attr_mcname_sized; typedef struct thrd_attr_mwcname { thrd_attr_kind kind; const wchar_t* name; } thrd_attr_mwcname; typedef struct thrd_attr_mwcname_sized { thrd_attr_kind kind; size_t size; const wchar_t* name; } thrd_attr_mwcname_sized; typedef struct thrd_attr_c8name { thrd_attr_kind kind; const char8_t* name; } thrd_attr_c8name; typedef struct thrd_attr_c8name_sized { thrd_attr_kind kind; size_t size; const char8_t* name; } thrd_attr_c8name_sized; typedef struct thrd_attr_c16name { thrd_attr_kind kind; const char16_t* name; } thrd_attr_c16name; typedef struct thrd_attr_c16name_sized { thrd_attr_kind kind; size_t size; const char16_t* name; } thrd_attr_c16name_sized; typedef struct thrd_attr_c32name { thrd_attr_kind kind; const char32_t* name; } thrd_attr_c32name; typedef struct thrd_attr_c32name_sized { thrd_attr_kind kind; size_t size; const char32_t* name; } thrd_attr_c32name_sized; typedef struct thrd_attr_stack_size { thrd_attr_kind kind; size_t size; } thrd_attr_stack_size; typedef struct thrd_attr_detached { thrd_attr_kind kind; bool detached; } thrd_attr_detached; typedef int(thrd_attr_err_func_t)(const thrd_attr_kind[static 1], int err, void* err_func_arg); int thrd_create_attrs(thrd_start_func func, void* arg, size_t n, const thrd_attr_kind *attrs[static n]); int thrd_create_attrs_err(thrd_start_func func, void* arg, size_t n, const thrd_attr_kind *attrs[static n], thrd_attr_err_func_t* err_func, void* err_func_arg);3.1. Thread Attribute Kind & ABI-Resistance
The thread attribute kind enumeration has 65,536 reserved values [0, 65â535] for the standard, and 2,147,418,112 reserved values [65â636, 2â147â483â647] for implementation-defined attributes. An implementation can add more attributes to cover more cases and information that the standard could not conceivably provide a unified interface for, such as:
stack address + stack size (POSIX Threads);
starting "Suspended" (Win32 Threads);
setting implementation-specific processor/core affinity (Win32 and POSIX Threads);
setting implementation-specific scheduler or thread priority (many different values for POSIX, fixed set of enumeration values for Win32);
setting commit vs. reserved stack size values (Win32 Threads);
and so much more. 65 thousand values for the standard more than covers the set of interfaces WG14 could possibly manage to standardize (one per standard structure), and 2.1 billion values (one per implementation-defined structure) gives implementations plenty of room to play around and not conflict with each other (hopefully they are nice and send each other e-mails so avoid potential conflicts, as they should in this day and age).
This design is also ABI-resistant. If structures need to change, rather than trying to change them in-line and suffering from a problem of adding members or otherwise disturbing how reads and writes of such structures will be treated, a new one can be added seamlessly and without pain both on the standard side and the implementation side.
Each enumeration is given a fixed value to prevent ABI disagreements for serialization purposes between platforms. The values themselves do not matter, and so any of them can be adjusted. The enumeration should fit a 32-bit signed integer, and so platforms with a 16 bit integer may need to use implementation-specific tricks or rely on C23âs enumeration specification abilities.
3.2. Thread AttributesThread attributes are structures paired with one of the enumeration names that represent a specific kind of transformation to a thread. The standard will define several thread attribute structures, though the specification says that an implementation can process -- but ignore -- the desired effects of each attribute. This is mostly to allow for embedded implementations that do not care for keeping this information around, and keeps the cost of this paper to 0 for implementations that do not care.
There are 14 different provided structures and 14 different enumeration constants to go with them:
thrd_attr_stack_size
: takes a size_t
and communicates the size (in bytes) of the stack.
thrd_attr_detached
: takes a bool
and communicates that the thread should be detached at the very start.
thrd_attr_c8name
, thrd_attr_c8name_sized
: takes a const char8_t *
or a const char8_t *
+ size_t
, respectively. It represents a UTF-8-encoded name. The name is converted to the desired internal encoding of the thread name. Must be terminated by a null char8_t
value, or not contain a null char8_t
value within the buffer denoted by the range, respectively. The pointer may be null.
thrd_attr_c16name
, thrd_attr_c16name_sized
: takes a const char16_t *
or a const char16_t *
+ size_t
, respectively. It represents a UTF-16-encoded name. The name is converted to the desired internal encoding of the thread name. Must be terminated by a null char16_t
value, or not contain a null char16_t
value within the buffer denoted by the range, respectively. The pointer may be null.
thrd_attr_c32name
, thrd_attr_c32name_sized
: takes a const char32_t *
or a const char32_t *
+ size_t
, respectively. It represents a UTF-32-encoded name. The name is converted to the desired internal encoding of the thread name. Must be terminated by a null char32_t
value, or not contain a null char32_t
value within the buffer denoted by the range, respectively. The pointer may be null.
thrd_attr_mcname
, thrd_attr_mcname_sized
: takes a const char *
or a const char *
+ size_t
, respectively. It represents an execution encoding-encoded name. The name is converted to the desired internal encoding of the thread name. Must be terminated by a null char
value, or not contain a null char
value within the buffer denoted by the range, respectively. The pointer may be null.
thrd_attr_mwcname
, thrd_attr_mwcname_sized
: takes a const wchar_t *
or a const wchar_t *
+ size_t
, respectively. It represents a wide execution-encoded name. The name is converted to the desired internal encoding of the thread name. Must be terminated by a null wchar_t
value, or not contain a null wchar_t
value within the buffer denoted by the range, respectively. The pointer may be null.
thrd_attr_native_name
, thrd_attr_native_name_sized
: takes a const void *
or a const void *
+ size_t
, respectively, and has its value copied directly into the thread. Itâs performs no transformations or permutations on the name. The pointed-to data must not have a sequence of zero bytes of a length chosen by the implementation (typically 1 on POSIX implementations and 2 on Windows implementations). This is explicitly for sending data directly to the threading API without any conversions.
thrd_attr_stack_size
This attribute is necessary because most platforms have a way to set the stack size, but sometimes can only do it at the start of the thread. Therefore, it needs to be passed in at creation time and let the implementation decide how and when to apply it. There are additional APIs for controlling the entire stack (with both a pointer and a size), but this is not as universal so a thrd_attr_stack_storage
attribute with both a size_t
and a void *
are not being proposed.
Note that the size_t
passed by thrd_attr_stack_size
is, more or less, a suggestion: many platforms will change or round the value up to a lower limit, or make sure it is a multiple of an internal implementation size or alignment (e.g., page-aligned or 64-byte aligned). Additionally, implementations may also implement guard pages around the stack as well. Therefore, even if the implementation honors it, the final size is still entirely implementation-defined, and the specification is written to reflect this.
thrd_attr_detached
This attribute is necessary because some platforms (e.g., Windows/MSVC) have issues with getting the proper thread control rights after creating the thread from a different thread in order to properly detach the thread. With this passed to the creation of the thread, a thread can be detached properly and follow POSIX semantics on creation, whereas otherwise it might not work from sinde the given thrd_t
, as documented by Visual C++ Library Maintainer Charlie Barto|:
A key difference between our implementation and C11 threads implementations based on pthreads is that threads can not detach themselves using
thrd_current ()
andthrd_detach ()
. This is because of a fundamental difference in how threads work on Windows vs Unix descendants and we would require a shared datastructure that tracks thread handles to implement the typical behavior.
Given this behavior, itâs better to provide this as an on-creation technique, where the original threadâs HANDLE
is still present and this can be invoked properly.
thrd_attr_ { mwc / mc / c ( 8 | 16 | 32 | native ) name }
The name attributes are necessary because platforms differ wildly in how they can set the name. Some can only set the name inside of the thread after it has been started (many POSIX thread implementations); others can create a thread in suspended mode and then set all of the necessary information (Win32 Threads, IBM-styled POSIX threads).
Furthermore, the actual internal storage, encoding, and more of threads varies across implementations. Win32 stores 16-bit WCHAR
/ wchar_t
internally, which is more suitable to a UTF-16 or Wide Literal/Execution Encoding string on their platforms, while POSIX platforms tend to simply absorb any byte string with no encoding except that \ 0
is not part of it. Most of these APIs rely explicitly on null termination.
Thusly, to not unduly disadvantage any platform, we provide the 5 typical encodings that can be mapped to the internals of the implementation however they like. For example, POSIX platforms can take UTF-32, UTF-16, and Wide Execution encoded strings and convert them to UTF-8 or Execution encoded byte strings so that the null termination character is only a single byte and the whole name can be serialized properly. Windows can take UTF-32, UTF-8, and Execution encoded strings and convert them into 16-bit UTF-16/Wide Execution strings so that it has a proper 2-byte null terminator.
Finally, for individuals who feel confident that their name will closely match the platformâs semantics, there is a plain thrd_attr_native_name
, which holds a const void *
. This can just be copied directly into an implementation, and the consequences will be whatever happens.
As a very, very important point: the strings passed in through these functions have no lifetime implications after thrd_create_with_attrs
returns. They can be rewritten, changed, adjusted, or freed once the thrd_create_with_attrs
function returns: all implementations tend to copy the names into some form of internal data anyways.
If there is appetite to provide a string just via pointer where the lifetime of that string must be kept alive for the duration of the thread, additional attribute types can be created to offer that to standard users. The goal would, of course, be for implementations that do not have any internal storage to hold onto the smallest possible string VIA pointer alone and simply let the user manage both the data and the lifetime. However, we have encountered no platforms that have requested this hypothetical optimization, so a special thrd_attr_static_name
structure has not been provided.
get
-style API?"
We do not provide the get
/ query
APIs in this paper. Much like thread creation, there are various APIs for getting a thread name, or its priority, or whether or not its detached. Some do not provide any API at all (a few of the BSDs). Getters also include the issue of synchronization, or possible Time Of Check vs. Time Of Use (TOCTOU) issues.
We leave getter/query APIs to future papers after ironing out this paper.
3.4. "How does this API handle errors?"An important part of having thread attributes is recognizing that implementations have wildly different handling strategies, even for attributes that are spiritually the same on most platforms. For example, stack_size
is something that can be honored on all implementations we know about, including the Dreamcast Console implementation of threads. Unfortunately, the exact handling of the number actually differs on platforms.
Win32 thread implementations will round the value up as alignment or to meet a minimum stack size. But, POSIX thread implementations simply error and ignore the provided size, and in some versions of glibc it will round the value down for alignment purposes (despite that not being allowed by the specification). This fact means that a number passed in to thrd_attr_stack_size
and propagated through the thrd_create_attrs
function can and will silently fail on a POSIX implementation while working on a Win32 implementation.
The solution to this problem is the specification of a thrd_attr_err_func
function type, and taking a pointer to such a function in any given thrd_create_attrs_err (...)
. There will be cases where users do not care at all about attribute errors, either because they checked beforehand or because such failures donât really concern them at all and the usage of such attributes are just nonchalant suggestions: in those cases, users can pass a function accept_everything
to thrd_create_attrs_err (...)
, pass NULL
which will do the same thing, or simply call thrd_create_attrs
which will do the same thing.
Similarly, users can pick and choose the kinds of errors they care about:
#include <threads.h> #include <stdcountof.h> #include <stdio.h?> inline static int thrd_main(void* arg) { (void)arg; /* ... */ return 0; } int handle_attribute_errors(const thrd_attr_kind* attr_kind, int err, void* userdata) { (void)userdata; if (*attr_kind == thrd_attr_kind_c32name) { // we don't care if name is unrecognized: not critical to us printf("We could not set the name of the thread " "with a UTF-32 string (%d)", err); return thrd_success; } else if (*attr_kind == thrd_attr_kind_stack_size) { // this matters to us: pipe the error through return err; } // attribute we either do not know or do not care about: just assume success return thrd_success; } int main(void) { thrd_t t0 = {}; thrd_attr_c32name name_attr = { .kind = thrd_attr_kind_c32name, .name = U"meow?!" }; thrd_attr_stack_size stack_size_attr = { .kind = thrd_attr_kind_stack_size, .size = 1024, // this is too small for POSIX threads // and will cause an error }; // some random attribute to illustrate // that we don't recognize it, // and that we don't care. const struct thrd_attr_priority { thrd_attr_kind kind; int priority; } priority_attr = { // some custom attribute or whatever .kind = (ztdc_thrd_attr_kind)0x12345678, .priority = INT_MAX, }; const ztdc_thrd_attr_kind* attrs[] = { &priority_attr.kind, &stack_size_attr.kind, &name_attr.kind, }; int create_err = thrd_create_attrs_err( &t0, thrd_main, NULL, countof(attrs), attrs, handle_attribute_errors, NULL); assert(create_err == thrd_success); int res0 = 0; thrd_join(t0, &res0); assert(res0 == 0); return 0; }
This code will stop thread creation if stack_size_attr
is not handled properly (e.g., the implementation does not recognize it OR the implementation tries to set the stack size but reports an error, like pthread_attr_setstacksize
would). It will explicitly acknowledge and ignore an issue with the thread name (but ignore it for the purposes of the implementation). This gives users the ultimate control over what is going on, in the form of a final say on whether or not thread creation should proceed.
The function passed in, handle_attribute_errors
, is invoked on the same thread as the call to thrd_create_attrs_err
. This is to prevent needing additional synchronization accesses and checks.
There are other ways this API can be shaped. Unfortunately, most of those changes are not worth their bang or their buck: see the library documentation here.
4. Implementation ExperienceThis was implemented in [ztd.thread] as a proof of concept. It is tested on Win32, MacOS/Darwin, and Ubuntu/glibc in an automated fashion (GitHub CI) and by-hand on Win32/ARM64, Debian/glibc, Debian/musl-libc, and FreeBSD.
Documentation for the library is contained here.
5. WordingThe following wording is against the latest draft of the C standard.
5.1. Modify §7.29.1 "Introduction" to add the new structures and an enumeration5.2. Add a new section §7.29.2⨠"Thread attributes" to make it rely on wording moved to other function...
thrd_start_twhich is the function pointer type
int ( * )( void * )
that is passed tothrd_create
to create a new thread;thrd_attr_kindwhich is an enumeration type that is compatible with
int_least32_t
and used to provide type associations for the functionsthrd_create_attrs
andthrd_create_attrs_err
;thrd_attr_err_func_twhich is the function pointer type
int ( const thrd_attr_kind * , int , void * )
that is passed tothrd_create_attrs_err
to handle errors in thread attribute application;typedef struct thrd_attr_native_name { thrd_attr_kind kind; const void* name; } thrd_attr_native_name; typedef struct thrd_attr_native_name_sized { thrd_attr_kind kind; size_t size; const void* name; } thrd_attr_native_name_sized; typedef struct thrd_attr_mcname { thrd_attr_kind kind; const char* name; } thrd_attr_mcname; typedef struct thrd_attr_mcname_sized { thrd_attr_kind kind; size_t size; const char* name; } thrd_attr_mcname_sized; typedef struct thrd_attr_mwcname { thrd_attr_kind kind; const wchar_t* name; } thrd_attr_mwcname; typedef struct thrd_attr_mwcname_sized { thrd_attr_kind kind; size_t size; const wchar_t* name; } thrd_attr_mwcname_sized; typedef struct thrd_attr_c8name { thrd_attr_kind kind; const char8_t* name; } thrd_attr_c8name; typedef struct thrd_attr_c8name_sized { thrd_attr_kind kind; size_t size; const char8_t* name; } thrd_attr_c8name_sized; typedef struct thrd_attr_c16name { thrd_attr_kind kind; const char16_t* name; } thrd_attr_c16name; typedef struct thrd_attr_c16name_sized { thrd_attr_kind kind; size_t size; const char16_t* name; } thrd_attr_c16name_sized; typedef struct thrd_attr_c32name { thrd_attr_kind kind; const char32_t* name; } thrd_attr_c32name; typedef struct thrd_attr_c32name_sized { thrd_attr_kind kind; size_t size; const char32_t* name; } thrd_attr_c32name_sized; typedef struct thrd_attr_stack_size { thrd_attr_kind kind; size_t size; } thrd_attr_stack_size; typedef struct thrd_attr_detached { thrd_attr_kind kind; bool detached; } thrd_attr_detached;which represent standard thread attribute structures that are described in 7.29.2â¨;
...
The enumeration constants part of
thrd_attr_kind
arethrd_attr_kind_native_name = 0 thrd_attr_kind_native_name_sized = 1 thrd_attr_kind_mcname = 2 thrd_attr_kind_mcname_sized = 3 thrd_attr_kind_mwcname = 4 thrd_attr_kind_mwcname_sized = 5 thrd_attr_kind_c8name = 6 thrd_attr_kind_c8name_sized = 7 thrd_attr_kind_c16name = 8 thrd_attr_kind_c16name_sized = 9 thrd_attr_kind_c32name = 10 thrd_attr_kind_c32name_sized = 11 thrd_attr_kind_stack_size = 32 thrd_attr_kind_detached = 256 thrd_attr_kind_implementation_defined = 0xFFFFand are set as the value of the
kind
member field of thread attributes described in 7.29.2â¨. They provide a way to uniquely identify each thread attribute, except for thethrd_attr_kind_implementation_defined
which has no associated structure.
5.3. Modify §7.29.5.1 "TheDescription
The thread attribute enumeration and structures listed in the preceding subclause correspond to specific modifications that can be applied to a thread when passed as part of the
attrs
array forthrd_create_attrs
andthrd_create_attrs_err
function calls. Standard thread attributes are the structures and enumerations mentioned in this and the preceding subclause. Any other thread attribute structures and enumeration constants defined by the implementation as prescribed by this subclause are implementation thread attributes. The standard thread attributes shall be available when< threads . h >
is included, but the effects each has on any given thread are conditionally supported and implementation-defined. Implementation thread attributes may not be available when< threads . h >
is included and have implementation-defined effects, if any.For
thrd_create_attrs
andthrd_create_attrs_err
function calls, the behavior is unspecified if more than one ofthrd_attr_native_name
,thrd_attr_mcname
,thrd_attr_mwcname
,thrd_attr_c8name
,thrd_attr_c16name
,thrd_attr_c32name
, or any of their_sized
counterparts, are used in the sameattrs
array. The behavior is unspecified if more than one of any standard thread attribute is used in theattrs
array.With the exception of
thrd_attr_kind_implementation_defined
, for everythrd_attr_kind
enumeration constant defined in this document of the formthrd_attr_kind_X
, whereX
is the rest of the identifier, there is a correspondingthrd_attr_X
complete object of structure type. Thekind
member must be set to the correspondingthrd_attr_kind_X
enumeration constantâs value for everythrd_attr_X
structure before use with thethrd_create_attrs
andthrd_create_attrs_with
functions, otherwise the behavior is undefined.Each identifier of the form
thrd_attr_kind_X
, whereX
is the rest of the identifier, is reserved for use by this document as a thread attribute enumeration constant whose value shall be less thanthrd_attr_kind_implementation_defined
. Each identifier of the formthrd_attr_X
for the corresponding structure is also reserved by this document as a thread attribute structure. Thread attribute enumeration constants and structures defined by this document shall not haveX
begin with the character_
(U+005F LOW LINE). An implementation may define subsequentthrd_attr_kind_Y
enumeration constants as part of thethrd_attr_kind
enumerated type, whereY
is the rest of the identifier, for use as implementation-defined thread attributes. The value of such an enumeration constant shall be greater thanthrd_attr_kind_implementation_defined
.The thread attributes
thrd_attr_mcname
,thrd_attr_mwcname
,thrd_attr_c8name
,thrd_attr_c16name
, andthrd_attr_c32name
provide a thread with a name encoded in the execution, wide execution, UTF-8, UTF-16, and UTF-32 encodings (6.2.9), respectively, as a null terminated string. If the value of thename
field is a null pointer, then no change occurs. Otherwise, the value pointed to by thename
field must be valid for the function call. The thread attributes of the same name but suffixed with_sized
provide a thread with the same information, except that thename
field can be a non-null terminated pointer and whose size is denoted by the fieldsize
. For these_sized
thread attributes, thename
field may not contain an appropriately typed null terminator in the range denoted by thename
andsize
fields. The range denoted byname
, or byname
andsize
for the_sized
-suffixed thread attributes, are not accessed by the implementation after thethrd_create_attrs
orthrd_create_attrs_err
function calls return.The thread attribute
thrd_attr_native_name
provides an pointer toconst void
whose value is meant to be used directly by the implementation to set the name of the thread. It has an implementation-defined encoding. If thename
field is a null pointer, there is no effect. Otherwise, the pointer shall be null terminated by a sequence of 0 bytes. The number of 0-valued bytes that make up the sequence of that null terminator is implementation-defined. The thread attributethrd_attr_native_name_sized
is the same, except that the number of bytes in thename
field is equal to the value of thesize
field. Thename
field must not contain the implementation-defined null termination byte sequence in the range denoted by thename
andsize
fields. The range denoted byname
, or byname
andsize
forthrd_attr_native_name_sized
, are not accessed by the implementation after thethrd_create_attrs
orthrd_create_attrs_err
function calls return.Recommended Practice
The thread attributes
thrd_attr_mcname
,thrd_attr_mwcname
,thrd_attr_c8name
,thrd_attr_c16name
,thrd_attr_c32name
, and their_sized
-suffixed analogues, should have their names converted to any unspecified yet appropriate encoding, if necessary, and set as the name of the thread. The thread attributesthrd_attr_native_name
andthrd_attr_native_name_sized
should have their name set without any conversion, if possible, as the name of the thread. An implementation should make the name available when thread information, possibly obtained by unspecified or implementation-defined means, is inspected.The thread attribute
thrd_attr_stack_size
provides a recommendation for the size of the storage used for the thread with respect to automatic storage duration lifetime declarations for that thread.The thread attribute
thrd_attr_detached
provides a value which determines whether or not a thread should be created in the detached state, or should immediately be detached upon creation as-if by callingthrd_detach
with the thread that is being created.
thrd_create
function" to make it rely on wording moved to other function
5.4. Add a new sub-clause "§7.29.5.2⨠TheSynopsis
#include <threads.h> int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);Description
The
thrd_create
function creates a new thread executing func(arg). If thethrd_create
function succeeds, it sets the object pointed toby thr
to the identifier of the newly created thread. (A threadâs identifier can be reused for a different thread once the original thread has exited and either been detached or joined to another thread.) The completion of thethrd_create
function synchronizes with the beginning of the execution of the new thread.Returning from
func
has the same behavior as invokingthrd_exit
with the value returned fromfunc
.Returns
The
thrd_create
function returnsthrd_success
on success, orthrd_nomem
if no memory could be allocated for the thread requested, orthrd_error
if the request could not be honored.The
thrd_create
function returns and is equivalent tothrd_create_attrs_err ( thr , func , arg , 0 , nullptr , nullptr , nullptr )
.
thrd_create_attrs
function" after "The thrd_create
function"
5.5. Add a new sub-clause "§7.29.5.3⨠TheSynopsis
#include <threads.h> int thrd_create_attrs(thrd_t *thr, thrd_start_t func, void *arg, size_t attrs_n, const thrd_attr_kind* attrs[static attrs_n]);Description
The
thrd_create_attrs
function returns and is equivalent tothrd_create_attrs_err ( thr , func , arg , attrs_n , attrs , nullptr , nullptr )
.
thrd_create_attrs_err
function" after "The thrd_create_attrs
function"
5.6. Modify "§7.35.20 Threads" of "Future library directions"Synopsis
#include <threads.h> int thrd_create_attrs_err(thrd_t *thr, thrd_start_t func, void *arg, size_t attrs_n, const thrd_attr_kind *attrs[static attrs_n] thrd_attr_err_func_t *err_func, void *err_func_arg);Description
The
thrd_create_attrs_err
function creates a new thread executingfunc ( arg )
after applying any modifications to the thread through the thread attributes in theattrs
array, if any. Iferr_func
is a null pointer, this function behaves as iferr_func
points to an appropriately typed function that returnsthrd_success
no matter the input. If thethrd_create_attrs_err
function succeeds, it sets the object pointed to bythr
to the identifier of the newly created thread. (A threadâs identifier can be reused for a different thread once the original thread has exited and either been detached or joined to another thread.)If
attrs
is a null pointer, no thread attributes are processed. Ifattrs_n
is 0, no thread attributes are processed. Each pointerp
in the range[ attrs , attrs + attrs_n )
must point to a thread attribute or be a null pointer. Ifp
is a null pointer, it is ignored and has no effect. Otherwise, if* p
is a thread attribute that is not honored by the implementation,err_func
is called with the argumentsp
,thrd_error
, anderr_func_arg
. Otherwise, the implementation processes the attribute and affects the thread according to the semantics in 7.29.5.2â¨. If the implementation encounters an error during the processing,err_func
is invoked with:
the first argument as
p
;the second argument as an unspecified value of one of
thrd_error
,thrd_nomem
,thrd_timedout
, orthrd_busy
; and,the third argument as
err_func_arg
.
err_func
returns one ofthrd_error
,thrd_nomem
,thrd_timeout
, orthrd_busy
. Iferr_func
returns a value that is notthrd_success
,thrd_create_attrs_err
returns that value and the thread is not created.Returning from
func
has the same behavior as invokingthrd_exit
with the value returned fromfunc
. All thread attributes are processed before the completion ofthrd_create_attrs_err
.err_func
is always executed on the same thread that invokedthrd_create_attrs_err
. The completion of thethrd_create_attrs_err
function synchronizes with the beginning of the execution offunc
in the new thread.Returns
The
thrd_create_attrs_err
function returnsthrd_success
on success, orthrd_nomem
if no memory could be allocated for the thread requested, orthrd_error
if the request could not be honored.Recommended Practice
Implementations should pass the closest analogous error code from the
thrd_error
,thrd_nomem
,thrd_timedout
, orthrd_busy
enumeration constants that is related to any implementation-specific errors that occur during thread creation and thread attribute processing.
Function names, type names, and enumeration constants that begin with either
cnd_
,
mtx_
,
thrd_
, or
tss_
, and a lowercase letter are potentially reserved identifiers and may be added to the declarations in the
< threads . h >
header.
Identifiers of the formthrd_attr_X
andthrd_attr_kind_X
, whereX
is the rest of the identifier, are either:
reserved by this document, if
X
does not begin with_
(U+005F LOW LINE); orpotentially reserved by the implementation, if
X
does begin with_
(U+005F LOW LINE).
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4