<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=US-ASCII">
<title>C and C++ Thread Compatibility</title>
<style type="text/css">
td { vertical-align: top; }
</style>
</head>
<body>
<h1>C and C++ Thread Compatibility</h1>

<p>
ISO/IEC JTC1 SC22 WG14 N1423 - 2009-11-08
<br>
ISO/IEC JTC1 SC22 WG21 N2985 = 09-0175 - 2009-11-08
</p>

<p>
Lawrence Crowl, crowl@google.com, Lawrence@Crowl.org
</p>

<p>
<a href="#Introduction">Introduction</a><br>
<a href="#General">General Problems and Recommendations</a><br>
<a href="#Critical">Critical Compatiblity</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Self">Operations on Self</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Quick">Quick Exit</a><br>
<a href="#Important">Important Compatiblity</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#TLS">Thread-Local Storage</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Once">Call Once</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Mutex">Mutex</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Condition">Condition</a><br>
<a href="#Desirable">Desirable Compatiblity</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Thread">Thread</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#TSS">Thread-Specific Storage</a><br>
</p>

<p>
This paper revises WG14 N1414.
It includes comments, observations, and recommenations from various sources,
among them
Hans Boehm,
Peter Dimov,
Howard Hinnant,
Daniel Kr&uuml;gler,
Tom Plum,
Douglas Walls,
Anthony Williams,
and the Posix/C++ binding group.
Their contribution should not necessarily
be construed as an endorsement of anything within this paper.
Furthermore, 
this document contains observations and recommendations,
not a proposal.
</p>


<h2><a name="Introduction">Introduction</a></h2>

<p>
The compatibility between the C and C++ threading facilities
is important to many members of the respective communities.
There are at least three levels of compatibility:
critical, important, and desirable.
Of these, the C and C++ committees should
commit to achieving critical and important compatibility.
This paper analyses the compatiblity between current draft standards,
and recommends several actions to improve that compatibility.
</p>

<p>
The most useful kind of compatibility
is when an application header using thread facilities
can be included by and used from both languages.
Furthermore, it is desirable for C++ programs
to be able to use C++ syntax with objects from that header.
The recommendations within this paper support that goal.
</p>


<h2><a name="General">General Problems and Recommendations</a></h2>

<p>
There are several problems that span all facilities.
Later discussion may provide more specific discussion.
</p>

<dl>
<dt><strong>Incorporation</strong></dt>
<dd>
<p>
C++ does not recognize the C definitions.
</p>

<p>
<em>Recommendation:</em>
Functions in C but not in C++ should be incorporated by reference.
If the C standard happens before the C++ standard,
this reference will be within the standard.
Otherwise, this reference will be within a Technical Report
subsequent to the standard.
</p>
</dd>

<dt><strong>Representation</strong></dt>
<dd>
<p>
There is at present no guarantee that
C and C++ concurrency objects have the same representation.
</p>

<p>
<em>Recommendation:</em>
Where possible, make that guarantee,
preferably by using the same type name.
</p>
</dd>

<dt><strong>Initialization</strong></dt>
<dd>
<p>
The initialization of objects is not compatible.
In particular, the C++ default initialization syntax
fails to initialize C objects
and C++ does not recognize the C initialization functions.
Furthermore, the C standard fails to define
the result of access to a zero-initialized global concurrency object.
Well-defined behavior here is important
because of the indeterminate nature of intialization function order.
</p>

<p>
<em>Recommendation:</em>
C should specify the meaning of a zero-initialized synchronization object.
Preferably, the zero-initialization of such objects
should be the ready-to-use state.
Failing that, C should provide for
explicit static initialization of all concurrency objects.
C++ should add explicit initialization functions,
or, preferably, accept the C functions.
These functions should do no harm to a
object that has been default-initialized.
That is, the initialization functions are idempotent with constructors.
</p>
</dd>

<dt><strong>Copying and Assignment</strong></dt>
<dd>
<p>
C++ prevents copying from (including parameter passing)
and assignment to concurrency objects.
C fails to define the semantics of such actions.
</p>

<p>
<em>Recommendation:</em>
C should specify copying and assignment of such objects as undefined behavior.
</p>
</dd>

<dt><strong>Finalization</strong></dt>
<dd>
<p>
The finalization of objects is not compatible.
In particular, the C will not execute C++ destructors
and may therefore need an explicit finalization call.
</p>

<p>
<em>Recommendation:</em>
C++ should either add explicit finalization functions
or, preferably, accept the C functions.
These functions should do no harm on objects that are later destroyed.
That is, the finalization functions are idempotent with destructors.
</p>
</dd>

<dt><strong>Error Reporting</strong></dt>
<dd>
<p>
C reports errors through a return value.
C++ reports errors through exceptions.
</p>

<p>
<em>Recommendation:</em>
No action; these approaches are appropriate to each language.
</p>
</dd>

<dt><strong>Enumerations</strong></dt>
<dd>
<p>
C defines many functions with <code>int</code> parameter and return types,
even though the values correspond to enumerators.
This weakening of types reduces diagnostic capability.
</p>

<p>
<em>Recommendation:</em>
C should define enumeration types for mutex behavior and return status
and then use those in the definition of the functions.
</p>
</dd>

<dt><strong>Native Handle</strong></dt>
<dd>
<p>
C++ provides a mechanism to obtain the native operating-system handle
for various concurrency objects,
which makes platform-specific tweaks possible.
C provides no such mechanism.
</p>

<p>
<em>Recommendation:</em>
C should consider adding this facility.
</p>
</dd>
</dl>


<h2><a name="Critical">Critical Compatiblity</a></h2>

<p>
The critical level of compatibility
is that a C thread is a C++ thread,
and that operations on one's own thread
apply to that thread regardless of the language
used to create the thread.
While it is difficult to state this requirement normatively,
it is a reasonable expectation on the part of users.
</p>


<h3><a name="Self">Operations on Self</a></h3>

<p>
The operations that a thread may perform on itself are as follows.
</p>

<table border=1>
<thead>
<tr><th>C</th><th>C++</th></tr>
</thead>

<tbody>
<tr>
<td><code>void thrd_yield( void);</code></td>
<td><code>std::this_thread::yield();</code></td>
</tr>

<tr>
<td><code>void thrd_sleep( const&nbsp;xtime&nbsp;*xt);</code></td>
<td><code>template&lt; class&nbsp;Clock, class&nbsp;Duration&gt;<br>
void std::this_thread::sleep_until(
const&nbsp;chrono::time_point&lt;
Clock, Duration&gt;&amp;&nbsp;abs_time);</code></td>
</tr>

<tr>
<td><em>no&nbsp;facility</em></td>
<td><code>template&lt; class&nbsp;Rep, class&nbsp;Period&gt;<br>
void std::this_thread::sleep_for(
const&nbsp;chrono::duration&lt;
Rep, Period&gt;&amp;&nbsp;rel_time);</code></td>
</tr>

<tr>
<td><code>void thrd_exit( int&nbsp;res);</code></td>
<td><em>no&nbsp;facility</em></td>
</tr>
</tbody>
</table>

<p></p>

<dl>
<dt><strong>Duration</strong>
<dd>
<p>
C is missing a duration sleep function.
It may appear that one could easily
synthesize the behavior by adding an offset to 
the result of <code>xtime_get</code>,
but subtle effects of clock resetting
make that synthesis not accurate.
</p>

<p>
<em>Recommendation:</em>
No action at this time.
</p>
</dd>

<dl>
<dt><strong>Thread Exit</strong></dt>
<dd>
<p>
C++ is missing a <code>thread_exit</code> function.
</p>

<p>
<em>Recommendation:</em>
There seems to be general agreement among C++ experts
that a thread exit that does not unwind the stack will be a resource leak.
This leak is likely to also exist in C
unless the programmers are very careful.
The issue does not apply to process exit
because the operating system
generally cleans up resources on process exit anyway.
Further, "uncatchable" exceptions also seem to not help.
Therefore, any
So, either C should not define <code>thread_exit</code>
or C++ should define a thread exit function
that throws some standard exception.
Programmers would need to ensure that the exeception is handled reasonably.
</p>
</dd>

</dl>


<h3><a name="Quick">Quick Exit</a></h3>

<p>
The operations that applications may use to exit the program
without synchronizing threads.
</p>

<table border=1>
<thead>
<tr><th>C</th><th>C++</th></tr>
</tbody>

<tbody>
<tr>
<td><code>int at_quick_exit( void&nbsp;(*f)(void));</code></td>
<td><code>extern "C" int at_quick_exit( void&nbsp;(*f)(void));<br>
extern "C++" int at_quick_exit( void&nbsp;(*f)(void));</code></td>
</tr>
<tr>
<td><code>void quick_exit( int&nbsp;status);</code></td>
<td><code>void quick_exit [[noreturn]]( int&nbsp;status);</code></td>
</tr>
</tbody>
</table>

<p>
The C standard is missing pending C++ clarifications,
but otherwise the standards are fully compatible.
</p>

<p>
<em>Recommendation:</em>
Track clarifications between the two languages.
</p>


<h2><a name="Important">Important Compatiblity</a></h2>

<p>
The important level of compatiblity
is that C and C++ code be able to communicate
through the same objects.
(We ignore atomic objects in this paper, and concentrate on other objects.)
</p>


<h3><a name="TLS">Thread-Local Storage</a></h3>

<p>
The facilities for thread-duration variables are as follows.
</p>

<table border=1>
<thead>
<tr><th>C</th><th>C++</th></tr>
</tbody>

<tbody>
<tr>
<td><code>_Thread_local</code></td>
<td><code>thread_local</code></td>
</tr>
</tbody>
</table>

<p></p>

<dl>
<dt><strong>Keyword</strong></dt>
<dd>
<p>
The C storage class specifier for thread-local storage
is <code>_Thread_local</code>.
In contrast, the C++ specifier is <code>thread_local</code>.
These are not compatible.
</p>

<p>
<em>Recommendation:</em>
Add an adaptation header to C,
much like much like <code>&lt;stdbool&gt;</code>,
that <code>#define</code>s <code>thread_local</code>
as <code>_Thread_local</code>.
In C++, this header would be empty.
Some C headers may not be able to include this adaptation header
for legacy reasons,
so C++ should add <code>_Thread_local</code>
as an alternate keyword for <code>thread_local</code>.
</p>

</dd>

<dt><strong>Remote Access</strong></dt>
<dd>
<p>
In C++, thread-local variables can only be named by the current thread,
but they can be accessed indirectly from any thread.
In contrast, access to C thread-local variables from another thread
is implementation defined.
This behavior is one-way compatible &mdash;
programs obeying C rules will execute correctly under C++.
</p>

<p>
<em>Recommendation:</em>
No change.
</p>
</dd>

<dt><strong>Local Variables</strong>
<dd>
<p>
In C++, inline function definitions
may contain static and thread storage duration variable definitions.
In C, they may not.
This behavior is one-way compatible &mdash;
programs obeying C rules will execute correctly under C++.
</p>

<p>
<em>Recommendation:</em>
No change.
</p>
</dd>

<dt><strong>Destruction</strong>
<dd>
<p>
C++ supports thread-local variables with destructors.
C has no equivalent concept.
At the coarse level,
there is no incompatiblity as C types have trivial destructors.
</p>

<p>
<em>Observation:</em>
C++ may introduce user-level facilities
for controling the timing of destruction,
which would introduce additional overhead
on thread-local variables with non-trivial destructors
and may introduce additional overhead
on thread-local variables with trivial destructors, i.e. C types.
Such additional implementation may be incompatible
with existing <code>__thread</code> implementations.
</p>

<p>
<em>Recommendation:</em>
If C++ introduces a mechanism for <code>thread_local</code>
that is incompatible with existing <code>__thread</code> variables,
C++ should consider supporting two such facilities.
</p>
</dd>

<dt><strong>Signals</strong></dt>
<dd>
<p>
In both C and C++, there is no guarantee
that a signal will be handled by any particular thread,
and therefore signal handlers
must not rely on the identity of thread-local storage.
This behavior is fully compatible.
</p>

<p>
<em>Recommendation:</em>
No change.
</p>
</dd>
</dl>


<h3><a name="Once">Call Once</a></h3>

<p>
The facilities for executing a function once are as follows.
</p>

<table border=1>
<thead>
<tr><th>C</th><th>C++</th></tr>
</tbody>

<tbody>
<tr>
<td><code>typedef <var>object-type</var> once_flag;</code></td>
<td><code>struct once_flag;</code></td>
</tr>

<tr>
<td><code>once_flag var = ONCE_FLAG_INIT;</code></td>
<td><code>once_flag var;</code></td>
</tr>

<tr>
<td><code>void call_once( once_flag&nbsp;*flag, void&nbsp;(*func)(void));</code></td>
<td><code>template&lt; class&nbsp;Callable, class&nbsp;...Args&gt;<br>
void call_once( once_flag&amp;&nbsp;flag,
Callable&nbsp;func, Args&amp;&amp;...&nbsp;args);</code></td>
</tr>
</tbody>
</table>

<p></p>

<dl>
<dt><strong>Type Name</strong></dt>
<dd>
<p>
The types are compatible,
provided the C standard typedefs <code>once_flag</code>
to <code>struct once_flag</code>.
</p>

<p>
<em>Recommendation:</em>
No change.
</p>
</dd>

<dt><strong>Initialization</strong></dt>
<dd>
<p>
The initialization of <code>once_flag</code> objects is not compatible.
In particular, the C++ syntax fails to initialize a C object
and C++ does not recognize the C initialization syntax.
(The C standard fails to define
the result of access to an uninitialized <code>once_flag</code> object.)
</p>

<p>
<em>Recommendation:</em>
C should specify the meaning of an unitialized <code>once_flag</code>.
Preferably, it should define zero-initialization as not-yet-executed.
C++ should add <code>constexpr</code> constructor
accepting a <code>ONCE_FLAG_INIT</code> value.
</p>
</dd>


<h3><a name="Mutex">Mutex</a></h3>

<p>
The facilities for mutual exclusion are as follows.
</p>

<table border=1>
<thead>
<tr><th>C</th><th>C++</th></tr>
</tbody>

<tbody>
<tr>
<td><code>typedef <var>object-type</var> mtx_t;</code></td>
<td><code>class&nbsp;mutex;</code>
<code>class&nbsp;recursive_mutex;</code>
<code>class&nbsp;timed_mutex;</code>
<code>class&nbsp;recursive_timed_mutex;</code></td>
</tr>

<tr>
<td><code>int mtx_init( mtx_t&nbsp;*mtx, int&nbsp;type);</code><br>
given a <code>type</code> of
<code>mtx_plain</code>, <code>mtx_timed</code>, <code>mtx_try</code>,
<code>mtx_plain|mtx_recursive</code>, <code>mtx_timed|mtx_recursive</code>,
or <code>mtx_try|mtx_recursive</code>
</td>
<td>default constructor</td>
</tr>

<tr>
<td><code>void mtx_destroy( mtx_t&nbsp;*mtx);</code></td>
<td>destructor</td>
</tr>

<tr>
<td><code>int mtx_unlock( mtx_t&nbsp;*mtx);</code></td>
<td><code>void <var>mutex</var>::unlock();</td>
</tr>

<tr>
<td><code>int mtx_lock( mtx_t&nbsp;*mtx);</code></td>
<td><code>void <var>mutex</var>::lock();</td>
</tr>

<tr>
<td><code>int mtx_trylock( mtx_t&nbsp;*mtx);</code></td>
<td><code>void <var>mutex</var>::try_lock();</td>
</tr>

<tr>
<td><code>int mtx_timedlock( mtx_t&nbsp;*mtx,
const&nbsp;xtime&nbsp;*xt);</code></td>
<td><code>
template&lt; class&nbsp;Clock, class&nbsp;Duration&gt;<br>
bool <var>mutex</var>::try_lock_until(
const&nbsp;chrono::time_point&lt; Clock, Duration&gt;&amp;&nbsp;abs_time);</code></td>
</tr>

<tr>
<td>no&nbsp;facility</td>
<td><code>
template&lt; class&nbsp;Rep, class&nbsp;Period&gt;<br>
bool <var>mutex</var>::try_lock_for(
const&nbsp;chrono::duration&lt; Rep, Period&gt;&amp;&nbsp;rel_time);</code></td>
</tr>
</tbody>
</table>

<p></p>

<dl>
<dt><strong>Behavior</strong></dt>
<dd>
<p>
C defines the behavior of a mutex object by initialization.
C++ defines the behavior by static type.
This is a serious incompatibility.
</p>

<p>
<em>Observation:</em>
The C approach may incur implementation inefficiencies on some platforms
for the plain mutex use.
The implementation on Mac OS X is known to be less efficient.
</p>

<p>
<em>Observation:</em>
The performance of many concurrent applications
is strongly affected by the time to obtain and release an uncontended lock.
The C++ <code>lock_guard</code>
was designed expressly to minimize that time
by avoiding any conditional execution.
A mutex type with dynamic behavior
will necessarily reintroduce conditional execution.
</p>

<p>
<em>Observation:</em>
In the multiple-type approach,
if you have a recursive mutex,
you cannot pass it to a function requiring a plain mutex.
In C++, this problem is generally solved
by making the function a template function.
That solution is not available to C.
</p>

<p>
<em>Recommendation:</em>
C and C++ should agree on a strategy for specifying mutex behavior.
Two main approaches have been suggested.
</p>
<ul>
<li>
Make the C type correspond to <code>recursive_timed_mutex</code>.
This approach does not address any performance problems in C.
</li>
<li>
Split the C type into separate types corresponding to the C++ types.
</li>
</ul>

<p>
</p>
</dd>

<dt><strong>Type Names</strong></dt>
<dd>
<p>
The mutex type names are incompatible,
but that problem is secondary to the above problem.
</p>

<p>
<em>Recommendation:</em>
C and C++ should agree on the type name(s).
Failing that,
C++ should define the C names as typedefs to the C++ classes.
</p>
</dd>

<dt><strong>Initialization</strong></dt>
<dd>
<p>
C does not specify the semantics of zero-initialized mutexes.
C++ initializes mutexes by construction.
C initializes mutexes with a separately called function.
These approaches are incompatible.
</p>

<p>
<em>Recommendation:</em>
C should define zero-initialization as unlocked.
C++ should define an initialization function,
even if that function is redundant with respect to construction.
At the very least,
C++ should provide specific semantics
when incorporating the C library by reference.
</p>

<p>
<em>Observation:</em>
This idempotent initialization may introduce overhead.
</p>

</dd>

<dt><strong>Finalization</strong></dt>
<dd>
<p>
C++ destroys mutexes by destruction.
C destroys mutexes with a separately called function.
These approaches are incompatible.
</p>

<p>
<em>Recommendation:</em>
C++ should define a destroy function,
even if that function is redundant with respect to destruction.
At the very least,
C++ should provide specific semantics
when incorporating the C library by reference.
</p>

<p>
<em>Observation:</em>
This idempotent initialization may introduce overhead.
</p>

</dd>

<dt><strong>Try Lock</strong></dt>
<dd>
<p>
C defines mutexes with a try-lock operation as a separate kind of mutex,
whereas C++ incorporates that operation into all mutexes.
This separation seems unnecessarily restrictive.
</p>

<p>
<em>Recommendation:</em>
C should remove <code>mtx_timed</code>
and permit <code>mtx_trylock</code> on all mutexes.
</p>
</dd>

<dt><strong>Duration Lock</strong></dt>
<dd>
<p>
C is missing a duration lock function.
See the sleep function discussion.
</p>

<p>
<em>Recommendation:</em>
No action at this time.
</p>
</dd>
</dl>


<h3><a name="Condition">Condition</a></h3>

<p>
The facilities for conditional waiting are as follows.
</p>

<table border=1>
<thead>
<tr><th>C</th><th>C++</th></tr>
</tbody>

<tbody>
<tr>
<td><code>typedef <var>object-type</var> cnd_t;</code></td>
<td><code>class&nbsp;condition_variable;</code></td>
</tr>

<tr>
<td><code>int cnd_init( cnd_t&nbsp;*cond);</code></td>
<td>default constructor</td>
</tr>

<tr>
<td><code>void cnd_destroy( cnd_t&nbsp;*cond);</code></td>
<td>destructor</td>
</tr>

<tr>
<td><code>int cnd_signal( cnd_t&nbsp;*cond);</code></td>
<td><code>void condition_variable::notify_one();</td>
</tr>

<tr>
<td><code>int cnd_broadcast( cnd_t&nbsp;*cond);</code></td>
<td><code>void condition_variable::notify_all();</td>
</tr>

<tr>
<td><code>int cnd_wait( cnd_t&nbsp;*cond, mtx_t&nbsp;*mtx);</code></td>
<td><code>void condition_variable::wait( unique_lock&lt; mutex&gt;&nbsp;lock);</td>
</tr>

<tr>
<td><code>int cnd_timedwait( cnd_t&nbsp;*cond, mtx_t&nbsp;*mtx,
const&nbsp;xtime&nbsp;*xt);</code></td>
<td><code>
template&lt; class&nbsp;Clock, class&nbsp;Duration&gt;<br>
bool condition_variable::wait_until( unique_lock&lt; mutex&gt;&nbsp;lock,
const&nbsp;chrono::time_point&lt; Clock, Duration&gt;&amp;&nbsp;abs_time);</code></td>
</tr>

<tr>
<td><em>no&nbsp;facility</em></td>
<td><code>
template&lt; class&nbsp;Rep, class&nbsp;Period&gt;<br>
bool condition_variable::wait_for( unique_lock&lt; mutex&gt;&nbsp;lock,
const&nbsp;chrono::duration&lt; Rep, Period&gt;&amp;&nbsp;rel_time);</code></td>
</tr>
</tbody>
</table>

<p></p>

<dl>
<dt><strong>Type Names</strong></dt>
<dd>
<p>
The C and C++ type names are incompatible.
</p>

<p>
<em>Recommendation:</em>
C and C++ should agree on the type name.
Failing that,
C++ should define the C name as a typedef to the C++ class.
</p>
</dd>

<dt><strong>Initialization</strong></dt>
<dd>
<p>
C does not specify the semantics of zero-initialized condition variables.
C++ initializes condition variables by construction.
C initializes condition variables with a separately called function.
These approaches are incompatible.
</p>

<p>
<em>Recommendation:</em>
C should define zero-initialization as no notifications.
C++ should define an initialization function,
even if that function is redundant with respect to construction.
At the very least,
C++ should provide specific semantics
when incorporating the C library by reference.
</p>
</dd>

<dt><strong>Finalization</strong></dt>
<dd>
<p>
C++ destroys condition variables by destruction.
C destroys condition variables with a separately called function.
These approaches are incompatible.
</p>

<p>
<em>Recommendation:</em>
C++ should define a destroy function,
even if that function is redundant with respect to destruction.
At the very least,
C++ should provide specific semantics
when incorporating the C library by reference.
</p>
</dd>

<dt><strong>Duration Wait</strong></dt>
<dd>
<p>
C is missing a duration wait function.
See the sleep function discussion.
</p>

<p>
<em>Recommendation:</em>
No action at this time.
</p>
</dd>
</dl>


<h2><a name="Desirable">Desirable Compatiblity</a></h2>

<p>
The desirable level of compatibility
is that C and C++ can operate on each other's threads.
</p>

<h3><a name="Thread">Thread</a></h3>

<p>
The facilities for creating and managing threads are as follows.
</p>

<table border=1>
<thead>
<tr><th>C</th><th>C++</th></tr>
</tbody>

<tbody>
<tr>
</tr>
<td><code>typedef <var>object-type</var> thrd_t;</code></td>
<td><code>class&nbsp;thread;</code></td>
</tr>

<tr>
<td><code>typedef int (*thrd_start_t)( void*);<br>
int thrd_create( thrd_t *thr, thrd_start_t&nbsp;func, void&nbsp;*arg);</code></td>
<td><code>thread::thread( template&lt; class F&gt; explicit thread( F&nbsp;f);</code></dt>
</tr>

<tr>
<td><em>no&nbsp;facility</em></td>
<td><code>bool thread::joinable();</code></td>
</tr>

<tr>
<td><code>int thrd_join( thrd_t&nbsp;thr, int&nbsp;*res);</code></td>
<td><code>void thread::join();</code></td>
</tr>

<tr>
<td><code>int thrd_detach( thrd_t&nbsp;thr);</code></td>
<td><code>void thread::detach();</code></td>
</tr>

<tr>
<td><em>not&nbsp;applicable</em>
<td><code>thread::id thread::get_id()</code></td>
</tr>

<tr>
<td><code>thrd_t thrd_current( void);</code></td>
<td><code>thread::id this_thread::get_id();</code></td>
</tr>

<tr>
<td><code>int thrd_equal( thrd_t&nbsp;thr0, thrd_t&nbsp;thr1);</code></td>
<td><code>bool operator==( thread::id&nbsp;x, thread::id&nbsp;y);</code></td>
</tr>

<tr>
<td><em>no&nbsp;facility</em>
<td>other <code>thread::id</code> relational operators</td>
</tr>
</tbody>
</table>

<p></p>

<dl>
<dt><strong>Type Approach</strong></dt>
<dd>
<p>
C provides operations on threads through a handle type.
In contrast, C++ provides operations directly on a move-only object type.
C++ does provide a handle type,
but operations on it are limited to identity checks.
These approaches are not directly compatible.
Because these types are not compatible,
there is no mechanism to operate on threads created in C++ from C
or vice versa.
</p>

<p>
<em>Observation:</em>
The move-only approach taken by C++ is simply not available directly in C.
However, C could restrict the use of <code>thrd_t</code>
to correspond to a move-only type.
The primary issue is whether the move-only approach
has sufficient value to justify the approach in both languages,
the approach in neither language,
or an incompatibility between languages.
</p>

<p>
<em>Recommendation:</em>
Make the C++ <code>std::thread::id</code> type
be a typedef to the same type as the C <code>thrd_t</code> typedef.
This recommendation does open an avenue
to joining/detaching a <code>thread</code>
without owning the <code>thread</code> object
via using <code>thrd_join</code> or <code>thrd_detach</code>
on the <code>std::thread::id</code>.
</p>

<p>
<em>Observation:</em>
The recommendation above removes the strong guarantee
of the C++ thread type.
</p>

<p>
<em>Recommendation:</em>
C should add a distinct thread_id_t</code> type
which is compatible with <code>std::thread::id</code>,
along with a <code>thrd_get_id()</code> function.
<code>thrd_current</code> should return this <code>thread_id_t</code> type,
not <code>thrd_t</code>.
</p>

</dd>

<dt><strong>Null Values</strong></dt>
<dd>
<p>
The C++ types <code>thread</code> and <code>thread::id</code>
have null values.
The C types do not.
This value is important for data structures referencing threads.
</p>

<p>
<em>Recommendation:</em>
C should define the syntax for defining a null <code>thrd_t</code>.
Preferably, one would obtain the null value from zero initialization.
C should define <code>thrd_t</code> comparison
to work with these null values.
</p>
</dd>

<dt><strong>Joinable Query</strong></dt>
<dd>
<p>
C++ provides a query on <code>thread</code>
to see if it is still legally joinable.
C has no such facility.
This function is related to the null-value issue.
</p>

<p>
<em>Recommendation:</em>
C should define such a function.
</p>
</dd>

<dt><strong>Thread Function Return</strong></dt>
<dd>
<p>
In C, thread functions may return an <code>int</code>,
which is passed through to the return value of <code>thrd_join</code>.
In C++, any return value is lost.
</p>

<p>
<em>Recommendation:</em>
There are two possible recommendations.
First, do nothing.
Second,
note that the return value is intended to support thread exit;
so if thread exit is not supported,
simply remove the return value from the thread return.
</p>
</dd>
</dl>

<h3><a name="TSS">Thread-Specific Storage</a></h3>

<p>
The facilities for thread-specific storage are as follows.
</p>

<table border=1>
<thead>
<tr><th>C</th><th>C++</th></tr>
</tbody>

<tbody>
<tr>
</tr>
<td><code>typedef <var>object-type</var> tss_t;</code></td>
<td><em>no&nbsp;facility</em>
</tr>

<tr>
<td><code>#define TSS_DTOR_ITERATIONS
<var>integer-constant-expression</var></code></td>
<td><em>no&nbsp;facility</em></td>
</tr>

<tr>
<td><code>typedef void (*tss_dtor_t)( void*)</code></td>
<td><em>no&nbsp;facility</em></td>
</tr>

<tr>
<td><code>int tss_create( tss_t&nbsp;*key, tss_dtor_t&nbsp;dtor);</code></td>
<td><em>no&nbsp;facility</em></td>
</tr>

<tr>
<td><code>void tss_delete( tss_t&nbsp;key);</code></td>
<td><em>no&nbsp;facility</em></td>
</tr>

<tr>
<td><code>void *tss_get( tss_t&nbsp;key);</code></td>
<td><em>no&nbsp;facility</em></td>
</tr>

<tr>
<td><code>int tss_set( tss_t&nbsp;key, void&nbsp;*val);</code></td>
<td><em>no&nbsp;facility</em></td>
</tr>
</tbody>
</table>

<p>
C++ does not provide thread-specific storage.
</p>

<p>
<em>Observation</em>
C++ requires that
<code>thread_local</code> destructors
run <em>before</em> <code>atexit</code> handlers,
whereas POSIX TSD destructors run as the last code executed by the thread,
<em>after</em> <code>atexit</code> handlers
if the current thread called <code>exit</code>.
It looks like the C functions
are intended to map cleanly onto their POSIX equivalent,
which would imply that
they would run after C++ <code>thread_local</code> destructors,
not before.
</p>

<p>
<em>Recommendation:</em>
When C++ incorporates the C library by reference,
it should define the thread-specific-storage destructors
execution relative to destructors for thread-local objects.
On possibility is to not define this ordering.
</p>

</body>
</html>
