﻿<html>
<head>
    <title>Proposed Text for Chapter 30, Thread Support Library [threads]</title>
    <meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema" />
    <meta http-equiv="Content-Language" content="en-us" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body bgcolor="#ffffff">
    <address>
        Document number: N2178=07-0038</address>
    <address>
        Programming Language C++, Evolution and Library Subgroups</address>
    <address>
        &nbsp;</address>
    <address>
        Peter Dimov, &lt;<a href="mailto:pdimov@pdimov.com">pdimov@pdimov.com</a>&gt;</address>
    <address>
        &nbsp;</address>
    <address>
        2007-03-03</address>
    <h1>
        Proposed Text for Chapter 30, Thread Support Library [threads]</h1>
    <ul>
        <li><a href="#overview">Overview</a></li>
        <li><a href="#proposed">Proposed Text</a></li>
        <li><a href="#principles">Design Principles and Assumptions</a></li>
        <li><a href="#decisions">Design Decisions</a></li>
        <li><a href="#implementability">Implementability</a></li>
    </ul>
    <h2>
        <a name="overview">I. Overview</a></h2>
    <p>
        This document presents a complete proposal for Chapter 30, Thread Support Library,
        of the C++ standard. It is based on the threading portion of ISO/IEC 9945:2003,
        also known as "POSIX threads" or "pthreads". Part of it builds on a previous paper
        of mine, N2090=06-0160, whereas the rest of the C++ interface is loosely based on
        Boost.Threads, Howard Hinnant's suggestion to template <em>std::condition</em> on
        the mutex type, as well as on countless discussions on the Boost mailing lists and
        the committee reflectors, and contains contributions from too many people for me
        to be able to list.</p>
    <h2>
        <a name="proposed">II. Proposed Text</a></h2>
    <h3>
        Chapter 30, Threading Support Library [threads]</h3>
    <p>
        This clause describes facilities that C++ programs may use to launch or control
        threads and to synchronize multiple threads.</p>
    <h4>
        Definitions</h4>
    <p>
        Throughout this chapter, the term ISO/IEC 9945 shall refer to ISO/IEC 9945:2003
        with ISO/IEC 9945-2:2003-Cor 1:2004 applied.</p>
    <h4>
        Summary</h4>
    <p>
        The library provides a C interface and a C++ interface to the thread support facilities.
        Unless otherwise specified, the interface through which a facility is accessed does
        not affect its semantics.</p>
    <p>
        The header <em>&lt;pthread.h&gt;</em> defines the C interface. It is compatible
        with the header of the same name defined by ISO/IEC 9945.</p>
    <p>
        The header <em>&lt;thread&gt;</em> defines the C++ interface.</p>
    <h4>
        Header &lt;pthread.h&gt; synopsis</h4>
    <pre>extern "C"
{

#define CLOCK_REALTIME <em>unspecified</em>
#define CLOCK_MONOTONIC <em>unspecified</em>

struct timespec;
typedef <em>unspecified</em> clockid_t;

int clock_gettime( clockid_t clock_id, struct timespec * tp );
int nanosleep( const struct timespec * rqtp, struct timespec * rmtp );

#define SCHED_FIFO <em>unspecified</em>
#define SCHED_RR <em>unspecified</em>
#define SCHED_OTHER <em>unspecified</em>

struct sched_param;

int sched_get_priority_max( int policy );
int sched_get_priority_min( int policy );
int sched_yield( void );

#define PTHREAD_CANCEL_ASYNCHRONOUS <em>unspecified</em>
#define PTHREAD_CANCEL_ENABLE <em>unspecified</em>
#define PTHREAD_CANCEL_DEFERRED <em>unspecified</em>
#define PTHREAD_CANCEL_DISABLE <em>unspecified</em>
#define PTHREAD_CANCELED <em>unspecified</em>
#define PTHREAD_COND_INITIALIZER <em>unspecified</em>
#define PTHREAD_CREATE_DETACHED <em>unspecified</em>
#define PTHREAD_CREATE_JOINABLE <em>unspecified</em>
#define PTHREAD_MUTEX_DEFAULT <em>unspecified</em>
#define PTHREAD_MUTEX_ERRORCHECK <em>unspecified</em>
#define PTHREAD_MUTEX_INITIALIZER <em>unspecified</em>
#define PTHREAD_MUTEX_NORMAL <em>unspecified</em>
#define PTHREAD_MUTEX_RECURSIVE <em>unspecified</em>
#define PTHREAD_ONCE_INIT <em>unspecified</em>
#define PTHREAD_PROCESS_SHARED <em>unspecified</em>
#define PTHREAD_PROCESS_PRIVATE <em>unspecified</em>

typedef <em>unspecified</em> pthread_attr_t;
typedef <em>unspecified</em> pthread_cond_t;
typedef <em>unspecified</em> pthread_condattr_t;
typedef <em>unspecified</em> pthread_key_t;
typedef <em>unspecified</em> pthread_mutex_t;
typedef <em>unspecified</em> pthread_mutexattr_t;
typedef <em>unspecified</em> pthread_once_t;
typedef <em>unspecified</em> pthread_rwlock_t;
typedef <em>unspecified</em> pthread_rwlockattr_t;
typedef <em>unspecified</em> pthread_t;

int pthread_attr_init( pthread_attr_t * attr );
int pthread_attr_destroy( pthread_attr_t * attr );
int pthread_attr_getdetachstate( const pthread_attr_t * attr, int * state );
int pthread_attr_setdetachstate( pthread_attr_t * attr, int state );
int pthread_attr_getschedparam( const pthread_attr_t * attr, struct sched_param * param );
int pthread_attr_setschedparam( pthread_attr_t * attr, const struct sched_param * param );
int pthread_attr_getstacksize( const pthread_attr_t * attr, size_t * size );
int pthread_attr_setstacksize( pthread_attr_t * attr, size_t size );
int pthread_attr_getguardsize( const pthread_attr_t * attr, size_t * guardsize );
int pthread_attr_setguardsize( pthread_attr_t * attr, size_t guardsize );

int pthread_create( pthread_t * thread, const pthread_attr_t * attr, void *(*start_routine)(void *), void * arg );
int pthread_detach( pthread_t thread );

int pthread_join( pthread_t thread, void ** value_ptr );
void pthread_exit( void * value_ptr );

int pthread_equal( pthread_t t1, pthread_t t2 );
pthread_t pthread_self( void );

int pthread_cancel( pthread_t thread );

int pthread_setcancelstate( int state, int * oldstate );
int pthread_setcanceltype( int type, int * oldtype );

void pthread_testcancel( void );

#define pthread_cleanup_push( routine, arg ) <em>unspecified</em>
#define pthread_cleanup_pop( execute ) <em>unspecified</em>

void * pthread_getspecific( pthread_key_t key );
int pthread_setspecific( pthread_key_t key, const void * value );

int pthread_key_create( pthread_key_t * key, void (*destructor)(void *) );
int pthread_key_delete( pthread_key_t key );

int pthread_mutexattr_init( pthread_mutexattr_t * attr );
int pthread_mutexattr_destroy( pthread_mutexattr_t * attr );
int pthread_mutexattr_gettype( const pthread_mutexattr_t * attr, int * type );
int pthread_mutexattr_settype( pthread_mutexattr_t * attr, int type );
int pthread_mutexattr_getpshared( const pthread_mutexattr_t * attr, int * pshared );
int pthread_mutexattr_setpshared( pthread_mutexattr_t * attr, int pshared );

int pthread_mutex_init( pthread_mutex_t * mutex, const pthread_mutexattr_t * attr );
int pthread_mutex_destroy( pthread_mutex_t * mutex );
int pthread_mutex_lock( pthread_mutex_t * mutex );
int pthread_mutex_timedlock( pthread_mutex_t * mutex, const struct timespec * abstime );
int pthread_mutex_trylock( pthread_mutex_t * mutex );
int pthread_mutex_unlock( pthread_mutex_t * mutex );

int pthread_condattr_init( pthread_condattr_t * attr );
int pthread_condattr_destroy( pthread_condattr_t * attr );
int pthread_condattr_getpshared( const pthread_condattr_t * attr, int * pshared );
int pthread_condattr_setpshared( pthread_condattr_t * attr, int pshared );
int pthread_condattr_getclock( const pthread_condattr_t * attr, clockid_t * clock_id );
int pthread_condattr_setclock( pthread_condattr_t * attr, clockid_t clock_id );

int pthread_cond_init( pthread_cond_t * cond, const pthread_condattr_t * attr );
int pthread_cond_destroy( pthread_cond_t * cond );
int pthread_cond_signal( pthread_cond_t * cond );
int pthread_cond_broadcast( pthread_cond_t * cond );
int pthread_cond_timedwait( pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec * abstime );
int pthread_cond_wait( pthread_cond_t * cond, pthread_mutex_t * mutex );

int pthread_rwlockattr_destroy( pthread_rwlockattr_t * attr );
int pthread_rwlockattr_init( pthread_rwlockattr_t * attr );
int pthread_rwlockattr_getpshared( const pthread_rwlockattr_t * attr, int * pshared );
int pthread_rwlockattr_setpshared( pthread_rwlockattr_t * attr, int pshared );

int pthread_rwlock_destroy( pthread_rwlock_t * rwlock );
int pthread_rwlock_init( pthread_rwlock_t * rwlock, const pthread_rwlockattr_t * attr );
int pthread_rwlock_rdlock( pthread_rwlock_t * rwlock );
int pthread_rwlock_timedrdlock( pthread_rwlock_t * rwlock, const struct timespec * abstime );
int pthread_rwlock_timedwrlock( pthread_rwlock_t * rwlock, const struct timespec * abstime );
int pthread_rwlock_tryrdlock( pthread_rwlock_t * rwlock );
int pthread_rwlock_trywrlock( pthread_rwlock_t * rwlock );
int pthread_rwlock_unlock( pthread_rwlock_t * rwlock );
int pthread_rwlock_wrlock( pthread_rwlock_t * rwlock );

int pthread_once( pthread_once_t * once_control, void (*init_routine)(void) );

// C++ support extensions (optional)

#define _POSIX_CXX09_EXTENSIONS

int pthread_less_np( pthread_t t1, pthread_t t2 );
size_t pthread_hash_np( pthread_t t1 );

int pthread_attach_np( pthread_t thread );

int pthread_once2_np( pthread_once_t * once_control, void (*init_routine)(void*), void * arg );

int pthread_join2_np( pthread_t thread );
int pthread_tryjoin2_np( pthread_t thread );
int pthread_timedjoin2_np( pthread_t thread, const struct timespec * abstime );

int pthread_attr_copy_np( pthread_attr_t * target, pthread_attr_t const * source );
int pthread_mutexattr_copy_np( pthread_mutexattr_t * target, pthread_mutexattr_t const * source );
int pthread_condattr_copy_np( pthread_condattr_t * target, pthread_condattr_t const * source );
int pthread_rwlockattr_copy_np( pthread_rwlockattr_t * target, pthread_rwlockattr_t const * source );

} // extern "C"
</pre>
    <p>
        Unless otherwise specified, the symbols, types, functions and macros defined by
        <em>&lt;pthread.h&gt;</em> shall have semantics as described in ISO/IEC 9945.</p>
    <p>
        The synopsis shows symbols as being defined as macros for presentation purposes.
        An implementation is allowed to define the symbols as integral constants or enumerated
        types.</p>
    <p>
        The functions declared by <em>&lt;pthread.h&gt;</em> may also have masking macros
        with the same semantics. <em>pthread_cleanup_push</em> and <em>pthread_cleanup_pop</em>
        shall always be defined as macros and may have no function declarations.</p>
    <p>
        The implementation shall ensure that the functions that accept a pointer to a function
        are callable with a pointer to a function having C++ linkage. The implementation
        is allowed to add function overloads with C++ linkage for this purpose.</p>
    <p>
        The behavior of a C++ program that enables asynchronous cancelation for a thread
        that has a non-POF as its start routine (<em>[support.runtime]/6</em>) is undefined.</p>
    <p>
        If the <em>init_routine</em> invoked by <em>pthread_once</em> throws an exception,
        the exception shall be propagated to the caller of <em>pthread_once</em> and the
        effect on <em>once_control</em> shall be as if <em>pthread_once</em> was never called.</p>
    <p>
        The inclusion of <em>&lt;pthread.h&gt;</em> in a translation unit reserves certain
        identifiers to the implementation as specified by ISO/IEC 9945. In particular, all
        symbols beginning with <em>PTHREAD_</em>, <em>pthread_</em>, <em>SCHED_</em> and
        <em>sched_</em> are reserved to the implementation.</p>
    <p>
        <em>pthread_exit( value_ptr )</em> should behave as if it throws an exception <em>std::thread_exit(
            value_ptr )</em>.</p>
    <p>
        Acting on a cancelation request should behave as if it unwinds the stack in response
        to an <em>std::thread_cancel</em> being thrown.</p>
    <p>
        If an exception of type <em>std::thread_exit</em> or <em>std::thread_cancel</em>
        is caught and not rethrown, the program should resume its normal operation. In particular,
        if the stack unwinding was initiated by acting on a cancelation request, the thread
        should revert to its normal state and cancelation should be reenabled as if by a
        call to <em>pthread_setcancelstate( PTHREAD_CANCEL_ENABLE )</em>.</p>
    <p>
        [<em>Note: </em>ISO/IEC 9945 requires that cancelation is disabled as if by a call
        to <em>pthread_setcancelstate( PTHREAD_CANCEL_DISABLE )</em> before a cancelation
        request is acted upon. The preceding requirement undoes this operation. <em>--end note</em>]</p>
    <p>
        The handlers installed by <em>pthread_cleanup_push</em> should be invoked in response
        to any C++ exception as if it were a cancelation exception.</p>
    <h4>
    </h4>
    <h4>
        C++ support extensions (optional)</h4>
    <p>
        The implementation is encouraged but not required to meet some additional requirements
        and provide additional functions in order to enable more efficient integration with
        the C++ interface.</p>
    <p>
        The requirements in this section are optional, but if provided, they shall be implemented
        as described.</p>
    <p>
        The implementation shall define the macro <em>_POSIX_CXX09_EXTENSIONS</em> if it
        meets the requirements of this section.</p>
    <p>
        The <em>pthread_t</em> type shall have a null value, obtained via value initialization.
        A null <em>pthread_t</em> shall refer to the null thread and shall not compare equal
        to any other valid <em>pthread_t</em> value.</p>
    <p>
        A thread shall have an associated reference count. The initial value of the reference
        count shall be 2 for joinable threads and 1 for detached threads. The reference
        count shall be decreased by one by <em>pthread_join</em>, <em>pthread_detach</em>,
        and the thread ending. When the reference count reaches zero, the <em>pthread_t</em>
        for the thread is invalidated and the storage for the thread should be reclaimed.</p>
    <p>
        [<em>Note:</em> In the absence of <em>pthread_attach_np</em> calls, this behavior
        is compatible with ISO/IEC 9945. <em>--end note</em>]</p>
    <p>
        <em>pthread_cancel,</em> <em>pthread_detach, pthread_attach_np, pthread_join2_np, pthread_tryjoin2_np
        </em>and <em>pthread_timedjoin2_np</em> shall accept the null thread as an argument
        and return 0 to indicate success; there shall be no other effects.</p>
    <p>
        Unless otherwise specified, all functions require their <em>pthread_t</em> arguments
        to be valid.</p>
    <p>
        The implementation shall support concurrent calls to functions operating on the
        same thread, unless the behavior of the sequential execution of the concurrent operations
        is undefined.</p>
    <pre>int pthread_less_np( pthread_t t1, pthread_t t2 );</pre>
    <p>
        <em>Returns:</em> an unspecified boolean value such that <em>pthread_less_np</em>
        is a total ordering on all valid <em>pthread_t</em> values, including null.</p>
    <pre>size_t pthread_hash_np( pthread_t t1 );</pre>
    <p>
        <em>Returns:</em> the hash value of its argument. Equal arguments shall yield the
        same result.</p>
    <pre>int pthread_attach_np( pthread_t thread );</pre>
    <p>
        <em>Effects:</em> Increases the reference count of <em>thread</em>.</p>
    <p>
        <em>Returns:</em> 0.</p>
    <pre>int pthread_once2_np( pthread_once_t * once_control, void (*init_routine)(void*), void * arg );</pre>
    <p>
        <em>Effects:</em> Equivalent to <em>pthread_once</em>, except that <em>arg</em>
        is passed to <em>init_routine</em>.</p>
    <pre>int pthread_join2_np( pthread_t thread );</pre>
    <p>
        <em>Effects:</em> Suspends execution of the calling thread until <em>thread</em>
        terminates. This function shall be a cancelation point.</p>
    <p>
        <em>Returns:</em> see <em>pthread_join</em>.</p>
    <p>
        [<em>Note:</em> <em>pthread_join2_np</em> is similar to <em>pthread_join</em>, but
        it does not affect the reference count of <em>thread</em> and is therefore safe
        to call multiple times, potentially from different threads. <em>--end note</em>]</p>
    <pre>int pthread_tryjoin2_np( pthread_t thread );</pre>
    <p>
        <em>Returns:</em> 0 if <em>thread</em> has terminated, <em>EBUSY</em> if it has
        not. May also return <em>EINVAL</em> or <em>ESRCH</em> as per the specification
        of <em>pthread_join</em>.</p>
    <pre>int pthread_timedjoin2_np( pthread_t thread, const struct timespec * abstime );</pre>
    <p>
        <em>Effects:</em> Suspends execution of the calling thread until <em>thread</em>
        terminates or <em>abstime</em> is reached. This function shall be a cancelation
        point.</p>
    <p>
        <em>Returns:</em> <em>ETIMEDOUT</em> if <em>abstime</em> is reached, one of the
        return values of <em>pthread_join</em> otherwise.</p>
    <pre>int pthread_attr_copy_np( pthread_attr_t * target, pthread_attr_t const * source );
int pthread_mutexattr_copy_np( pthread_mutexattr_t * target, pthread_mutexattr_t const * source );
int pthread_condattr_copy_np( pthread_condattr_t * target, pthread_condattr_t const * source );
int pthread_rwlockattr_copy_np( pthread_rwlockattr_t * target, pthread_rwlockattr_t const * source );</pre>
    <p>
        <em>Requires:</em> <em>source</em> and <em>target</em> refer to valid and initialized
        attribute objects.</p>
    <p>
        <em>Effects:</em> Copies the attributes from <em>*source</em> to <em>*target</em>.</p>
    <p>
        <em>Returns:</em> <em>0</em>. May return <em>EINVAL</em> if the requires clause
        is violated for consistency with the <em>pthread_*_get/set*</em> family of functions.</p>
    <p>
        <em>Postconditions:</em> <em>*target</em> is equivalent to <em>*source</em>.</p>
    <h4>
        Header &lt;thread&gt; synopsis</h4>
    <pre>namespace std
{

// Exceptions

class thread_exit;
class thread_cancel: public thread_exit;
class thread_error: public exception;
class lock_error: public exception;

// Synchronization primitives

class mutex_attr;
class mutex;

template&lt; class Mx &gt; class basic_lock;
typedef basic_lock&lt; mutex &gt; scoped_lock;

class condition_attr;
template&lt; class Mx &gt; class basic_condition;
template&lt;&gt; class basic_condition&lt; mutex &gt;;
typedef basic_condition&lt; mutex &gt; condition;

class rwlock_attr;
class rwlock;

typedef basic_lock&lt; rwlock &gt; write_lock;

template&lt; class Mx &gt; class basic_read_lock;
typedef basic_read_lock&lt; rwlock &gt; read_lock;

// Thread-safe initialization

template&lt; class F &gt; void call_once( pthread_once_t &amp; once_control, F f );
template&lt; class F, class A1, ..., class An &gt; void call_once( pthread_once_t &amp; once_control, F f, A1 a1, ..., An an );

// Thread control

class thread_attr;

namespace thread
{

class handle;

bool operator==( handle const &amp; h1, handle const &amp; h2 );
bool operator&lt;( handle const &amp; h1, handle const &amp; h2 );
size_t hash_value( handle const &amp; th );

template&lt; class F &gt; handle create( pthread_attr_t const * attr, F f );
template&lt; class F &gt; handle create( thread_attr const &amp; attr, F f );
template&lt; class F, class A1, ..., class An &gt; handle create( pthread_attr_t const * attr, F f, A1 a1, ..., An an );
template&lt; class F, class A1, ..., class An &gt; handle create( thread_attr const &amp; attr, F f, A1 a1, ..., An an );

template&lt; class F &gt; handle create( F f );
template&lt; class F, class A1, ..., class An &gt; handle create( F f, A1 a1, ..., An an );

handle self();

int join( handle const &amp; th );
int try_join( handle const &amp; th );
int timed_join( handle const &amp; th, timespec const &amp; abstime );

void exit();

void cancel( handle const &amp; th );
int set_cancel_state( int cs );
void test_cancel();

class disable_cancelation;

void sleep( timespec const &amp; reltime );

void yield();
void yield( unsigned k );

unsigned concurrency();

} // namespace thread

} // namespace std
</pre>
    <h5>
        Exceptions</h5>
    <pre>class thread_exit
{
private: <em>// exposition only</em>

    explicit thread_exit( void * pv );

public:

    void * value_ptr() const;
};
</pre>
    <p>
        The class <em>thread_exit</em>, constructed with an argument <em>pv</em>, represents
        stack unwinding initiated by a call to <em>pthread_exit( pv </em>) or <em>std::thread::exit(
            pv )</em>. It can only be constructed by the implementation.</p>
    <p>
        [<em>Note:</em> an implementation is allowed to defer constructing an object of
        type <em>thread_exit</em> until such an object is caught by a catch clause. <em>--end
            note</em>]</p>
    <pre>explicit thread_exit( void * pv );</pre>
    <p>
        <em>Postconditions:</em> <code>value_ptr() == pv</code>.</p>
    <pre>void * value_ptr() const;</pre>
    <p>
        <em>Returns:</em> The value <em>pv</em> with which this object has been constructed.</p>
    <pre>class thread_cancel: public thread_exit
{
private: <em>// exposition only</em>

    thread_cancel();
};
</pre>
    <p>
        The class <em>thread_cancel</em> represents stack unwinding initiated by a call
        to <em>pthread_cancel</em> or <em>std::thread::cancel</em>. It can only be constructed
        by the implementation.</p>
    <p>
        [<em>Note:</em> an implementation is allowed to defer constructing an object of
        type <em>thread_cancel</em> until such an object is caught by a catch clause. <em>--end
            note</em>]</p>
    <pre>thread_cancel();</pre>
    <p>
        <em>Postconditions:</em> <code>value_ptr() == PTHREAD_CANCELED</code>.</p>
    <pre>class thread_error: public exception
{
private: <em>// exposition only</em>

    int r_;

public:

    explicit thread_error( int r );
    virtual char const * what() throw();
    int error() const;
};
</pre>
    <p>
        The class <em>thread_error</em> is thrown by the implementation with an argument
        <em>r</em> when an underlying <em>pthread_</em> function returns an error code <em>r</em>.</p>
    <pre>explicit thread_error( int r );</pre>
    <p>
        <em>Effects:</em> intializes <em>r_</em> to <em>r</em>.</p>
    <pre>virtual char const * what() throw();</pre>
    <p>
        <em>Returns:</em> <code>"std::thread_error"</code>.</p>
    <pre>int error() const;</pre>
    <p>
        <em>Returns:</em> <em>r_</em>.</p>
    <pre>class lock_error: public exception
{
private: <em>// exposition only</em>

    int r_;

public:

    explicit lock_error( int r );
    virtual char const * what() throw();
    int error() const;
};
</pre>
    <p>
        The class <em>lock_error</em> is thrown by the lock classes when an error occurs.</p>
    <pre>explicit lock_error( int r );</pre>
    <p>
        <em>Effects:</em> intializes <em>r_</em> to <em>r</em>.</p>
    <pre>virtual char const * what() throw();</pre>
    <p>
        <em>Returns:</em> <code>"std::lock_error"</code>.</p>
    <pre>int error() const;</pre>
    <p>
        <em>Returns:</em> <em>r_</em>.</p>
    <h5>
        Synchronization primitives</h5>
    <pre>class mutex_attr
{
private: <em>// exposition only</em>

    pthread_mutexattr_t attr_;

public:

    explicit mutex_attr( pthread_mutexattr_t const * attr = 0 );
    ~mutex_attr();

    mutex_attr( mutex_attr const &amp; attr );
    mutex_attr &amp; operator=( mutex_attr const &amp; attr );

    operator pthread_mutexattr_t * ();
    operator pthread_mutexattr_t const * () const;

    int get_type() const;
    int set_type( int type );

    int get_pshared() const;
    int set_pshared( int pshared );
};
</pre>
    <p>
        The class <em>mutex_attr</em> provides a C++ equivalent of <em>pthread_mutexattr_t</em>.</p>
    <pre>explicit mutex_attr( pthread_mutexattr_t const * attr = 0 );</pre>
    <p>
        <em>Effects:</em> Initializes <em>attr_</em> as if by <code>pthread_mutexattr_init(
            &amp;attr_ )</code>. If <em>attr</em> is not <em>0</em>, calls <code>pthread_mutexattr_copy_np(
                &amp;attr_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error</code>.</p>
    <pre>~mutex_attr();</pre>
    <p>
        <em>Effects:</em> <code>pthread_mutexattr_destroy( &amp;attr_ )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>mutex_attr( mutex_attr const &amp; attr );</pre>
    <p>
        <em>Effects:</em> Initializes <em>attr_</em> as if by <code>pthread_mutexattr_init(
            &amp;attr_ )</code>, then calls <code>pthread_mutexattr_copy_np( &amp;attr_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error</code>.</p>
    <pre>mutex_attr &amp; operator=( mutex_attr const &amp; attr );</pre>
    <p>
        <em>Effects:</em> <code>pthread_mutexattr_copy_np( &amp;attr_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error</code>.</p>
    <pre>operator pthread_mutexattr_t * ();
operator pthread_mutexattr_t const * () const;</pre>
    <p>
        <em>Returns:</em> <code>&amp;attr_</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int get_type() const;</pre>
    <p>
        <em>Returns:</em> <code>type</code> as obtained by a call to <code>pthread_mutexattr_gettype(
            &amp;attr_, &amp;type )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int set_type( int type );</pre>
    <p>
        <em>Returns:</em> <code>pthread_mutexattr_settype( &amp;attr_, type )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int get_pshared() const;</pre>
    <p>
        <em>Returns:</em> <code>pshared</code> as obtained by a call to <code>pthread_mutexattr_getpshared(
            &amp;attr_, &amp;pshared )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int set_pshared( int pshared );</pre>
    <p>
        <em>Returns:</em> <code>pthread_mutexattr_setpshared( &amp;attr_, pshared )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>class mutex
{
private: <em>// exposition only</em>

   pthread_mutex_t mx_;
   
   mutex( mutex const &amp; );
   mutex &amp; operator=( mutex const &amp; );

public:

   explicit mutex( pthread_mutexattr_t const * attr = 0 );
   explicit mutex( int type );
   ~mutex();

   int lock();
   int try_lock();
   int timed_lock( timespec const &amp; abstime );
   int unlock();
};
</pre>
    <p>
        The class <em>mutex</em> provides a C++ equivalent of <em>pthread_mutex_t</em>.</p>
    <pre>explicit mutex( pthread_mutexattr_t const * attr = 0 );</pre>
    <p>
        <em>Effects:</em> <code>pthread_mutex_init( &amp;mx_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error( r )</code>, where <em>r</em> is the error returned
        by <em>pthread_mutex_init</em>.</p>
    <pre>explicit mutex( int type );</pre>
    <p>
        <em>Requires:</em> <em>type</em> is one of <em>PTHREAD_MUTEX_DEFAULT</em>, <em>PTHREAD_MUTEX_NORMAL</em>,
        <em>PTHREAD_MUTEX_ERRORCHECK</em>, or <em>PTHREAD_MUTEX_RECURSIVE</em>.</p>
    <p>
        <em>Effects:</em> <code>pthread_mutex_init( &amp;mx_, &amp;attr )</code>, where
        <em>attr</em> is an initialized object of type <em>pthread_mutexattr_t</em>, whose
        type attribute has been set to <em>type</em> as if by <code>pthread_mutexattr_settype(
            &amp;attr, type )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error( r )</code>, where <em>r</em> is the error returned
        by <em>pthread_mutex_init</em>.</p>
    <pre>~mutex();</pre>
    <p>
        <em>Effects:</em> <code>pthread_mutex_destroy( &amp;mx_ )</code>.</p>
    <pre>int lock();</pre>
    <p>
        <em>Returns:</em> <code>pthread_mutex_lock( &amp;mx_ )</code>.</p>
    <pre>int try_lock();</pre>
    <p>
        <em>Returns:</em> <code>pthread_mutex_trylock( &amp;mx_ )</code>.</p>
    <pre>int timed_lock( timespec const &amp; abstime );</pre>
    <p>
        <em>Returns:</em> <code>pthread_mutex_timedlock( &amp;mx_, &amp;abstime )</code>.</p>
    <pre>int unlock();</pre>
    <p>
        <em>Returns:</em> <code>pthread_mutex_unlock( &amp;mx_ )</code>.</p>
    <pre>template&lt; class Mx &gt; class basic_lock
{
private: <em>// exposition only</em>

    Mx * pmx_;
    bool locked_;
    
    basic_lock( basic_lock const &amp; );
    basic_lock &amp; operator=( basic_lock const &amp; );

public:

    typedef Mx mutex_type;

    explicit basic_lock( Mx &amp; mx, bool locked = true );
    ~basic_lock();

    void lock();
    bool try_lock();
    bool timed_lock( timespec const &amp; abstime );
    void unlock();

    bool locked() const;
    Mx * mutex();
};
</pre>
    <p>
        The class template <em>basic_lock</em> provides an exception-safe interface to mutex
        operations.</p>
    <pre>explicit basic_lock( Mx &amp; mx, bool locked = true );</pre>
    <p>
        <em>Effects:</em> initializes <em>pmx_</em> to <code>&amp;mx</code>. If <em>locked</em>
        is <em>true</em>, calls <code>lock()</code>.</p>
    <pre>~basic_lock();</pre>
    <p>
        <em>Effects:</em> if <em>locked_</em> is <em>true</em>, calls <code>unlock()</code>.</p>
    <pre>void lock();</pre>
    <p>
        <em>Requires:</em> <code>!locked()</code>.</p>
    <p>
        <em>Effects:</em> calls <code>pmx_-&gt;lock()</code>. If its return value <em>r</em>
        is 0, sets <em>locked_</em> to <em>true</em>, otherwise throws <code>lock_error( r )</code>.</p>
    <pre>bool try_lock();</pre>
    <p>
        <em>Requires:</em> <code>!locked()</code>.</p>
    <p>
        <em>Effects:</em> calls <code>pmx_-&gt;try_lock()</code>. If its return value <em>r</em>
        is 0, sets <em>locked_</em> to <em>true</em>, otherwise if <em>r</em> is not <em>EBUSY</em>,
        throws <code>lock_error( r )</code>.</p>
    <p>
        <em>Returns:</em> <em>locked_</em>.</p>
    <pre>bool timed_lock( timespec &amp; abstime );</pre>
    <p>
        <em>Requires:</em> <code>!locked()</code>.</p>
    <p>
        <em>Effects:</em> calls <code>pmx_-&gt;timed_lock( abstime )</code>. If its return
        value <em>r</em> is 0, sets <em>locked_</em> to <em>true</em>, otherwise if <em>r</em>
        is not <em>ETIMEDOUT</em>, throws <code>lock_error( r )</code>.</p>
    <p>
        <em>Returns:</em> <em>locked_</em>.</p>
    <pre>void unlock();</pre>
    <p>
        <em>Requires:</em> <code>locked()</code>.</p>
    <p>
        <em>Effects:</em> calls <code>pmx_-&gt;unlock()</code> and sets <em>locked_</em>
        to <em>false</em>. If the call to <code>pmx_-&gt;unlock()</code> returns nonzero,
        the behavior is implementation-defined, except that no exception shall be thrown.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>bool locked() const;</pre>
    <p>
        <em>Returns:</em> <em>locked_</em>.</p>
    <pre>Mx * mutex();</pre>
    <p>
        <em>Returns:</em> <em>pmx_</em>.</p>
    <pre>class condition_attr
{
private: <em>// exposition only</em>

    pthread_condattr_t attr_;

public:

    explicit condition_attr( pthread_condattr_t const * attr = 0 );
    ~condition_attr();

    condition_attr( condition_attr const &amp; attr );
    condition_attr &amp; operator=( condition_attr const &amp; attr );

    operator pthread_condattr_t * ();
    operator pthread_condattr_t const * () const;

    int get_pshared() const;
    int set_pshared( int pshared );

    clockid_t get_clock() const;
    int set_clock( clockid_t clock_id );
};
</pre>
    <p>
        The class <em>condition_attr</em> provides a C++ equivalent of <em>pthread_condattr_t</em>.</p>
    <pre>explicit condition_attr( pthread_condattr_t const * attr = 0 );</pre>
    <p>
        <em>Effects:</em> Initializes <em>attr_</em> as if by <code>pthread_condattr_init( &amp;attr_
            )</code>. If <em>attr</em> is not <em>0</em>, calls <code>pthread_condattr_copy_np(
                &amp;attr_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error</code>.</p>
    <pre>~condition_attr();</pre>
    <p>
        <em>Effects:</em> <code>pthread_condattr_destroy( &amp;attr_ )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>condition_attr( condition_attr const &amp; attr );</pre>
    <p>
        <em>Effects:</em> Initializes <em>attr_</em> as if by <code>pthread_condattr_init( &amp;attr_
            )</code>, then calls <code>pthread_condattr_copy_np( &amp;attr_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error</code>.</p>
    <pre>condition_attr &amp; operator=( condition_attr const &amp; attr );</pre>
    <p>
        <em>Effects:</em> <code>pthread_condattr_copy_np( &amp;attr_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error</code>.</p>
    <pre>operator pthread_condattr_t * ();
operator pthread_condattr_t const * () const;</pre>
    <p>
        <em>Returns:</em> <code>&amp;attr_</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int get_pshared() const;</pre>
    <p>
        <em>Returns:</em> <code>pshared</code> as obtained by a call to <code>pthread_condattr_getpshared(
            &amp;attr_, &amp;pshared )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int set_pshared( int pshared );</pre>
    <p>
        <em>Returns:</em> <code>pthread_condattr_setpshared( &amp;attr_, pshared )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>clockid_t get_clock() const;</pre>
    <p>
        <em>Returns:</em> <code>clock_id</code> as obtained by a call to <code>pthread_condattr_getclock(
            &amp;attr_, &amp;clock_id )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int set_clock( clockid_t clock_id );</pre>
    <p>
        <em>Returns:</em> <code>pthread_condattr_setclock( &amp;attr_, clock_id )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>template&lt;&gt; class basic_condition&lt; mutex &gt;
{
private: <em>// exposition only</em>

    pthread_cond_t cond_;
    
    basic_condition( basic_condition const &amp; );
    basic_condition &amp; operator=( basic_condition const &amp; );

public:

    explicit basic_condition( pthread_condattr_t const * attr = 0 );
    ~basic_condition();

    template&lt; class Lock &gt; int wait( Lock &amp; lock );
    template&lt; class Lock &gt; int timed_wait( Lock &amp; lock, timespec const &amp; abstime );

    int signal();
    int broadcast();
};
</pre>
    <p>
        The specialization <em>basic_condition&lt;mutex&gt;</em>, also available under the
        name <em>condition</em>, provides a C++ interface to a <em>pthread_cond_t</em> object.</p>
    <pre>explicit basic_condition( pthread_condattr_t const * attr = 0 );</pre>
    <p>
        <em>Effects:</em> <code>pthread_cond_init( &cond_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error( r )</code>, where <em>r</em> is the error returned
        by <em>pthread_cond_init</em>.</p>
    <pre>~basic_condition();</pre>
    <p>
        <em>Effects:</em> <code>pthread_cond_destroy( &cond_ )</code>.</p>
    <pre>template&lt; class Lock &gt; int wait( Lock &amp; lock );</pre>
    <p>
        <em>Requires:</em> <code>lock.locked()</code>; <code>Lock::mutex_type</code> shall
        be <code>std::mutex</code>.</p>
    <p>
        <em>Returns:</em> <code>pthread_cond_wait( &cond_, &lock.mutex()->mx_ )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_cancel</code>.</p>
    <p>
        [<em>Note:</em> in some cases, <em>wait</em> can return due to a <em>spurious wakeup</em>,
        without <em>signal</em> or <em>broadcast</em> being called on the condition variable.
        The caller is expected to recheck the predicate upon return. <em>--end note</em>]</p>
    <p>
        [<em>Example:</em></p>
    <pre>template&lt; class T &gt; class queue
{
private:

    std::condition cond_;
    std::mutex mx_;

    std::deque&lt; T &gt; data_;

public:

    void pop( T &amp; item )
    {
        std::scoped_lock lock( mx_ );

        while( data_.empty() ) cond_.wait( lock );

        item = data_.pop_front(); 
    }

    bool timed_pop( T &amp; item, timespec const &amp; abstime ); // see below

    void push( T const &amp; item ); // see below
};
</pre>
    <p>
        <em>--end example.</em>]</p>
    <pre>template&lt; class Lock &gt; int timed_wait( Lock &amp; lock, timespec &amp; abstime );</pre>
    <p>
        <em>Requires:</em> <code>lock.locked()</code>; <code>Lock::mutex_type</code> shall
        be <code>std::mutex</code>.</p>
    <p>
        <em>Returns:</em> <code>pthread_cond_timedwait( &cond_, &lock.mutex()->mx_, &amp;abstime
            )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_cancel</code>.</p>
    <p>
        [<em>Note:</em> in addition to spurious wakeups, the <em>timed_wait</em> function
        is susceptible to timing out even though the associated predicate may have become
        true. Re-checking the predicate on return is highly recommended. <em>--end note</em>]</p>
    <p>
        [<em>Example:</em></p>
    <pre>    bool timed_pop( T &amp; item, timespec const &amp; abstime )
    {
        std::scoped_lock lock( mx_ );

        while( data_.empty() )
        {
            int r = cond_.timed_wait( lock, abstime );

            assert( r == 0 || r == ETIMEDOUT );

            if( r == ETIMEDOUT )
            {
                if( data_.empty() )
                {
                    return false;
                }
                else
                {
                    break;
                }
            }
        }

        item = data_.pop_front();
        return true;
    }
</pre>
    <p>
        <em>--end example.</em>]</p>
    <pre>int signal();</pre>
    <p>
        <em>Returns:</em> <code>pthread_cond_signal( &cond_ )</code>.</p>
    <p>
        [<em>Example:</em></p>
    <pre>    void push( T const &amp; item )
    {
        {
            std::scoped_lock lock( mx_ );
            data_.push_back( item );
        }

        cond_.signal();
    }
</pre>
    <p>
        <em>--end example.</em>]</p>
    <pre>int broadcast();</pre>
    <p>
        <em>Returns:</em> <code>pthread_cond_broadcast( &cond_ )</code>.</p>
    <pre>template&lt; class Mx &gt; class basic_condition
{
public:

    explicit basic_condition( pthread_condattr_t const * attr = 0 );
    ~basic_condition();

    template&lt; class Lock &gt; int wait( Lock &amp; lock );
    template&lt; class Lock &gt; int timed_wait( Lock &amp; lock, timespec const &amp; abstime );

    int signal();
    int broadcast();
};
</pre>
    <p>
        The class template <em>basic_condition</em> represents a generalized condition variable
        that is not tied to a specific mutex type.</p>
    <pre>explicit basic_condition( pthread_condattr_t const * attr = 0 );</pre>
    <p>
        <em>Effects:</em> initializes <em>*this</em> using the attributes provided in <em>attr</em>.</p>
    <pre>~basic_condition();</pre>
    <p>
        <em>Effects:</em> destroys <em>*this</em>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>template&lt; class Lock &gt; int wait( Lock &amp; lock );</pre>
    <p>
        <em>Requires:</em> <code>lock.locked()</code>; <code>Lock::mutex_type</code> shall
        be <code>Mx</code>.</p>
    <p>
        <em>Effects:</em> Atomically unlocks <em>lock</em> and waits on this condition variable.
        Cancelation point.</p>
    <p>
        <em>Returns:</em> see the specification of <em>pthread_cond_wait</em>.</p>
    <p>
        <em>Throws:</em> <code>thread_cancel</code>.</p>
    <pre>template&lt; class Lock &gt; int timed_wait( Lock &amp; lock, timespec const &amp; abstime );</pre>
    <p>
        <em>Requires:</em> <code>lock.locked()</code>; <code>Lock::mutex_type</code> shall
        be <code>Mx</code>.</p>
    <p>
        <em>Effects:</em> Atomically unlocks <em>lock</em> and waits on this condition variable
        until <em>abstime</em> is reached. Cancelation point.</p>
    <p>
        <em>Returns:</em> see the specification of <em>pthread_cond_timedwait</em>.</p>
    <p>
        <em>Throws:</em> <code>thread_cancel</code>.</p>
    <pre>int signal();</pre>
    <p>
        <em>Effects:</em> Unblocks one of the threads waiting on this condition variable.</p>
    <p>
        <em>Returns:</em> see the specification of <em>pthread_cond_signal</em>.</p>
    <pre>int broadcast();</pre>
    <p>
        <em>Effects:</em> Unblocks all threads waiting on this condition variable.</p>
    <p>
        <em>Returns:</em> see the specification of <em>pthread_cond_broadcast</em>.</p>
    <p>
        [<em>Note:</em> a typical implementation of <em>basic_condition</em> is shown below:</p>
    <pre>template&lt; class Lock &gt; class __scoped_unlock
{
private:

    Lock &amp; lock_;

public:

    explicit __scoped_unlock( Lock &amp; lock ): lock_( lock )
    {
        assert( lock_.locked() );
        lock_.unlock();
    }

    ~__scoped_unlock()
    {
        lock_.lock();
    }
};

inline mutex_attr __mutexattr_from_condattr( pthread_condattr_t const * ca )
{
    mutex_attr ma;

    if( ca != 0 )
    {
        int pshared;

        if( pthread_condattr_getpshared( ca, &amp;pshared ) == 0 )
        {
            ma.set_pshared( pshared );
        }
    }

    return ma;
}

template&lt; class Mx &gt; class basic_condition
{
private:

    condition cond_;
    mutex mx_;

    basic_condition( basic_condition const &amp; );
    basic_condition &amp; operator=( basic_condition const &amp; );

public:

    basic_condition()
    {
    }

    explicit basic_condition( pthread_condattr_t const * attr ): cond_( attr ), mx_( __mutexattr_from_condattr( attr ) )
    {
    }

    template&lt; class Lock &gt; int wait( Lock &amp; lock )
    {
        assert( lock.locked() );

        scoped_lock lk( mx_ );
        __scoped_unlock&lt; Lock &gt; unlock( lock );

        return cond_.wait( lk );
    }

    template&lt; class Lock &gt; int timed_wait( Lock &amp; lock, timespec const &amp; abstime )
    {
        assert( lock.locked() );

        scoped_lock lk( mx_ );
        __scoped_unlock&lt; Lock &gt; unlock( lock );

        return cond_.timed_wait( lk, abstime );
    }

    int signal()
    {
        scoped_lock lock( mx_ );
        return cond_.signal();
    }

    int broadcast()
    {
        scoped_lock lock( mx_ );
        return cond_.broadcast();
    }
};
</pre>
    <p>
        <em>--end note.</em>]</p>
    <pre>class rwlock_attr
{
private: <em>// exposition only</em>

    pthread_rwlockattr_t attr_;

public:

    explicit rwlock_attr( pthread_rwlockattr_t const * attr = 0 );
    ~rwlock_attr();

    rwlock_attr( rwlock_attr const &amp; attr );
    rwlock_attr &amp; operator=( rwlock_attr const &amp; attr );

    operator pthread_rwlockattr_t * ();
    operator pthread_rwlockattr_t const * () const;

    int get_pshared() const;
    int set_pshared( int pshared );
};
</pre>
    <p>
        The class <em>rwlock_attr</em> provides a C++ equivalent of <em>pthread_rwlockattr_t</em>.</p>
    <pre>explicit rwlock_attr( pthread_rwlockattr_t const * attr = 0 );</pre>
    <p>
        <em>Effects:</em> Initializes <em>attr_</em> as if by <code>pthread_rwlockattr_init(
            &amp;attr_ )</code>. If <em>attr</em> is not <em>0</em>, calls <code>pthread_rwlockattr_copy_np(
                &amp;attr_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error</code>.</p>
    <pre>~rwlock_attr();</pre>
    <p>
        <em>Effects:</em> <code>pthread_rwlockattr_destroy( &amp;attr_ )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>rwlock_attr( rwlock_attr const &amp; attr );</pre>
    <p>
        <em>Effects:</em> Initializes <em>attr_</em> as if by <code>pthread_rwlockattr_init(
            &amp;attr_ )</code>, then calls <code>pthread_rwlockattr_copy_np( &amp;attr_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error</code>.</p>
    <pre>rwlock_attr &amp; operator=( rwlock_attr const &amp; attr );</pre>
    <p>
        <em>Effects:</em> <code>pthread_rwlockattr_copy_np( &amp;attr_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error</code>.</p>
    <pre>operator pthread_rwlockattr_t * ();
operator pthread_rwlockattr_t const * () const;</pre>
    <p>
        <em>Returns:</em> <code>&amp;attr_</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int get_pshared() const;</pre>
    <p>
        <em>Returns:</em> <code>pshared</code> as obtained by a call to <code>pthread_rwlockattr_getpshared(
            &amp;attr_, &amp;pshared )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int set_pshared( int pshared );</pre>
    <p>
        <em>Returns:</em> <code>pthread_rwlockattr_setpshared( &amp;attr_, pshared )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>class rwlock
{
private: <em>// exposition only</em>

    pthread_rwlock_t rwl_;
    rwlock( rwlock const &amp; );
    rwlock &amp; operator=( rwlock const &amp; );

public:

    explicit rwlock( pthread_rwlockattr_t const * attr = 0 );
    ~rwlock();

    int lock();
    int try_lock();
    int timed_lock( timespec const &amp; abstime );
    int unlock();

    int rdlock();
    int try_rdlock();
    int timed_rdlock( timespec const &amp; abstime );
    int rdunlock();
};
</pre>
    <p>
        The class <em>rwlock</em> represents the C++ interface of <em>pthread_rwlock_t</em>.</p>
    <pre>explicit rwlock( pthread_rwlockattr_t const * attr = 0 );</pre>
    <p>
        <em>Effects:</em> <code>pthread_rwlock_init( &amp;rwl_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error( r )</code>, where <em>r</em> is the error returned
        by <em>pthread_rwlock_init</em>.</p>
    <pre>~rwlock();</pre>
    <p>
        <em>Effects:</em> <code>pthread_rwlock_destroy( &amp;rwl_ )</code>.</p>
    <pre>int lock();</pre>
    <p>
        <em>Returns:</em> <code>pthread_rwlock_wrlock( &rwl_ )</code>.</p>
    <pre>int try_lock();</pre>
    <p>
        <em>Returns:</em> <code>pthread_rwlock_trywrlock( &rwl_ )</code>.</p>
    <pre>int timed_lock( timespec const &amp; abstime );</pre>
    <p>
        <em>Returns:</em> <code>pthread_rwlock_timedwrlock( &rwl_, &amp;abstime )</code>.</p>
    <pre>int unlock();</pre>
    <p>
        <em>Returns:</em> <code>pthread_rwlock_unlock( &rwl_ )</code>.</p>
    <pre>int rdlock();</pre>
    <p>
        <em>Returns:</em> <code>pthread_rwlock_rdlock( &rwl_ )</code>.</p>
    <pre>int try_rdlock();</pre>
    <p>
        <em>Returns:</em> <code>pthread_rwlock_tryrdlock( &rwl_ )</code>.</p>
    <pre>int timed_rdlock( timespec const &amp; abstime );</pre>
    <p>
        <em>Returns:</em> <code>pthread_rwlock_timedrdlock( &rwl_, &amp;abstime )</code>.</p>
    <pre>int rdunlock();</pre>
    <p>
        <em>Returns:</em> <code>pthread_rwlock_unlock( &rwl_ )</code>.</p>
    <pre>template&lt; class Mx &gt; class basic_read_lock
{
private: <em>// exposition only</em>

    Mx * pmx_;
    bool locked_;

    basic_read_lock( basic_read_lock const &amp; );
    basic_read_lock &amp; operator=( basic_read_lock const &amp; );

public:

    typedef Mx mutex_type;

    explicit basic_read_lock( Mx &amp; mx, bool locked = true );
    ~basic_read_lock();

    void lock();
    bool try_lock();
    bool timed_lock( timespec const &amp; abstime );
    void unlock();

    bool locked() const;
    Mx * mutex();
};
</pre>
    <p>
        The class template <em>basic_read_lock</em> provides an exception-safe interface
        for locking a mutex for reading.</p>
    <pre>explicit basic_read_lock( Mx &amp; mx, bool locked = true );</pre>
    <p>
        <em>Effects:</em> initializes <em>pmx_</em> to <code>&amp;mx</code>. If <em>locked</em>
        is <em>true</em>, calls <code>lock()</code>.</p>
    <pre>~basic_read_lock();</pre>
    <p>
        <em>Effects:</em> if <em>locked_</em> is <em>true</em>, calls <code>unlock()</code>.</p>
    <pre>void lock();</pre>
    <p>
        <em>Requires:</em> <code>!locked()</code>.</p>
    <p>
        <em>Effects:</em> calls <code>pmx_-&gt;rdlock()</code>. If its return value <em>r</em>
        is 0, sets <em>locked_</em> to <em>true</em>, otherwise throws <code>lock_error( r )</code>.</p>
    <pre>bool try_lock();</pre>
    <p>
        <em>Requires:</em> <code>!locked()</code>.</p>
    <p>
        <em>Effects:</em> calls <code>pmx_-&gt;try_rdlock()</code>. If its return value
        <em>r</em> is 0, sets <em>locked_</em> to <em>true</em>, otherwise if <em>r</em>
        is not <em>EBUSY</em>, throws <code>lock_error( r )</code>.</p>
    <p>
        <em>Returns:</em> <em>locked_</em>.</p>
    <pre>bool timed_lock( timespec const &amp; abstime );</pre>
    <p>
        <em>Requires:</em> <code>!locked()</code>.</p>
    <p>
        <em>Effects:</em> calls <code>pmx_-&gt;timed_rdlock( abstime )</code>. If its return
        value <em>r</em> is 0, sets <em>locked_</em> to <em>true</em>, otherwise if <em>r</em>
        is not <em>ETIMEDOUT</em>, throws <code>lock_error( r )</code>.</p>
    <p>
        <em>Returns:</em> <em>locked_</em>.</p>
    <pre>void unlock();</pre>
    <p>
        <em>Requires:</em> <code>locked()</code>.</p>
    <p>
        <em>Effects:</em> calls <code>pmx_-&gt;rdunlock()</code> and sets <em>locked_</em>
        to <em>false</em>. If the call to <code>pmx_-&gt;rdunlock()</code> returns nonzero,
        the behavior is implementation-defined, except that no exception shall be thrown.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>bool locked() const;</pre>
    <p>
        <em>Returns:</em> <em>locked_</em>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>Mx * mutex();</pre>
    <p>
        <em>Returns:</em> <em>pmx_</em>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <h5>
        Thread-safe initialization</h5>
    <pre>template&lt; class F &gt; void call_once( pthread_once_t &amp; once_control, F f );</pre>
    <p>
        <em>Requires:</em> <em>once_control</em> shall have static storage duration and
        be statically initialized to <em>PTHREAD_ONCE_INIT</em>. The expression <code>f()</code>
        shall be well-defined.</p>
    <p>
        <em>Effects:</em> <em>call_once</em> is equivalent to <em>pthread_once</em> with
        the call to <code>init_routine()</code> replaced by a call to <code>f()</code>.</p>
    <p>
        [<em>Note:</em> a typical implementation of <em>call_once</em> is shown below:</p>
    <pre>template&lt; class F &gt; void __call_once_helper( void * pv )
{
    F * pf = static_cast&lt; F * &gt;( pv );
    (*pf)();
}

template&lt; class F &gt; void call_once( pthread_once_t &amp; once_control, F f )
{
    pthread_once2_np( &amp;once_control, &__call_once_helper&lt;F&gt;, &f );
}
</pre>
    <p>
        <em>--end note.</em>]</p>
    <pre>template&lt; class F, class A1, ..., class An &gt; void call_once( pthread_once_t &amp; once_control, F f, A1 a1, ..., An an );</pre>
    <p>
        <em>Effects:</em> equivalent to <code>call_once( once_control, bind( f, a1, ..., an
            ) )</code>.</p>
    <h5>
        Thread control</h5>
    <pre>class thread_attr
{
private: <em>// exposition only</em>

    pthread_attr_t attr_;

public:

    explicit thread_attr( pthread_attr_t const * attr = 0 );
    ~thread_attr();

    thread_attr( thread_attr const &amp; attr );
    thread_attr &amp; operator=( thread_attr const &amp; attr );

    operator pthread_attr_t * ();
    operator pthread_attr_t const * () const;

    int get_detach_state() const;
    int set_detach_state( int detachstate );

    sched_param get_sched_param() const;
    int set_sched_param( sched_param const &amp; schedparam );

    size_t get_stack_size() const;
    int set_stack_size( size_t stacksize );

    size_t get_guard_size() const;
    int set_guard_size( size_t guardsize );
};
</pre>
    <p>
        The class <em>thread_attr</em> provides a C++ equivalent of <em>pthread_attr_t</em>.</p>
    <pre>explicit thread_attr( pthread_attr_t const * attr = 0 );</pre>
    <p>
        <em>Effects:</em> Initializes <em>attr_</em> as if by <code>pthread_attr_init( &amp;attr_
            )</code>. If <em>attr</em> is not <em>0</em>, calls <code>pthread_attr_copy_np( &amp;attr_,
                attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error</code>.</p>
    <pre>~thread_attr();</pre>
    <p>
        <em>Effects:</em> <code>pthread_attr_destroy( &amp;attr_ )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>thread_attr( thread_attr const &amp; attr );</pre>
    <p>
        <em>Effects:</em> Initializes <em>attr_</em> as if by <code>pthread_attr_init( &amp;attr_
            )</code>, then calls <code>pthread_attr_copy_np( &amp;attr_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error</code>.</p>
    <pre>thread_attr &amp; operator=( thread_attr const &amp; attr );</pre>
    <p>
        <em>Effects:</em> <code>pthread_attr_copy_np( &amp;attr_, attr )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_error</code>.</p>
    <pre>operator pthread_attr_t * ();
operator pthread_attr_t const * () const;</pre>
    <p>
        <em>Returns:</em> <code>&amp;attr_</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int get_detach_state() const;</pre>
    <p>
        <em>Returns:</em> <code>detachstate</code> as obtained by a call to <code>pthread_attr_getdetachstate(
            &amp;attr_, &amp;detachstate )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int set_detach_state( int detachstate );</pre>
    <p>
        <em>Returns:</em> <code>pthread_attr_setdetachstate( &amp;attr_, detachstate )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>sched_param get_sched_param() const;</pre>
    <p>
        <em>Returns:</em> <code>schedparam</code> as obtained by a call to <code>pthread_attr_getschedparam(
            &amp;attr_, &amp;schedparam )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int set_sched_param( sched_param const &amp; schedparam );</pre>
    <p>
        <em>Returns:</em> <code>pthread_attr_setschedparam( &amp;attr_, &amp;schedparam )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>size_t get_stack_size() const;</pre>
    <p>
        <em>Returns:</em> <code>stacksize</code> as obtained by a call to <code>pthread_attr_getstacksize(
            &amp;attr_, &amp;stacksize )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int set_stack_size( size_t stacksize );</pre>
    <p>
        <em>Returns:</em> <code>pthread_attr_setstacksize( &amp;attr_, stacksize )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>size_t get_guard_size() const;</pre>
    <p>
        <em>Returns:</em> <code>guardsize</code> as obtained by a call to <code>pthread_attr_getguardsize(
            &amp;attr_, &amp;guardsize )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int set_guard_size( size_t guardsize );</pre>
    <p>
        <em>Returns:</em> <code>pthread_attr_setguardsize( &amp;attr_, guardsize )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>class handle
{
private: <em>// exposition only</em>

    pthread_t pt_;

    void swap( handle const &amp; rhs );

public:

    handle();
    handle( handle const &amp; rhs );
    handle &amp; operator=( handle const &amp; rhs );
    ~handle();
};
</pre>
    <p>
        The class <em>handle</em> represents a handle to a thread.</p>
    <p>
        The operations on <em>handle</em> are described under the assumption that the C++
        support extensions are available. This is done to simplify the specification and
        does not imply that the extensions are required.</p>
    <pre>void swap( handle const &amp; rhs );</pre>
    <p>
        <em>Effects:</em> exchanges the contents of <em>*this</em> and <em>rhs</em>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>handle();</pre>
    <p>
        <em>Effects:</em> Initializes <em>pt_</em> to the null <em>pthread_t</em> value.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>handle( handle const &amp; rhs );</pre>
    <p>
        <em>Effects:</em> Initializes <em>pt_</em> to <em>rhs.pt_</em> and calls <code>pthread_attach_np(
            pt_ )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>handle &amp; operator=( handle const &amp; rhs );</pre>
    <p>
        <em>Effects:</em> <code>handle( rhs ).swap( *this )</code>.</p>
    <p>
        <em>Returns:</em> <code>*this</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>~handle();</pre>
    <p>
        <em>Effects:</em> <code>pthread_detach( pt_ )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>bool operator==( handle const &amp; h1, handle const &amp; h2 );</pre>
    <p>
        <em>Returns:</em> <code>pthread_equal( h1.pt_, h2.pt_ )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>bool operator&lt;( handle const &amp; h1, handle const &amp; h2 );</pre>
    <p>
        <em>Returns:</em> <code>pthread_less_np( h1.pt_, h2.pt_ )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>size_t hash_value( handle const &amp; th );</pre>
    <p>
        <em>Returns:</em> <code>pthread_hash_np( th.pt_ )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>template&lt; class F &gt; handle create( pthread_attr_t const * attr, F f );
template&lt; class F &gt; handle create( thread_attr const &amp; attr, F f );</pre>
    <p>
        <em>Effects:</em> Creates a new thread that executes <code>f()</code> and uses the
        attributes specified by <em>attr</em>. The attributes are interpreted as described
        in the specification of <em>pthread_create</em>, except that the new thread is always
        created as joinable.</p>
    <p>
        [<em>Note:</em> since the function returns a <em>handle</em> to the caller, the
        initial reference count of the new thread needs to take it into account. This is
        accomplished by creating a joinable thread. If the caller does not store the returned
        <em>handle</em>, the thread will be detached by <em>~handle</em>. <em>--end note</em>]</p>
    <p>
        <em>Returns:</em> A <em>handle</em> to the new thread.</p>
    <p>
        <em>Throws:</em> <em>thread_error</em> on failure.</p>
    <p>
        [<em>Note:</em> one possible implementation of <em>create</em> is shown below:</p>
    <pre>template&lt; class F &gt; void * __threadproc( void * pv )
{
    std::auto_ptr&lt; F &gt; pf( static_cast&lt; F * &gt;( pv ) );

    (*pf)();

    return 0;
}

template&lt; class F &gt; handle create( pthread_attr_t const * attr, F f )
{
    std::auto_ptr&lt;F&gt; pf( new F( f ) );

    pthread_t pt;
    int r;

    if( attr != 0 )
    {
        thread_attr attr2( attr );
        attr2.set_detach_state( PTHREAD_CREATE_JOINABLE );

        r = pthread_create( &pt, attr2, &__threadproc&lt;F&gt;, pf.get() );
    }
    else
    {
        r = pthread_create( &pt, 0, &__threadproc&lt;F&gt;, pf.get() );
    }

    if( r != 0 )
    {
        throw thread_error( r );
    }

    pf.release();

    return handle( pt, false ); // private constructor, does not call pthread_attach_np
}
</pre>
    <p>
        <em>--end note.</em>]</p>
    <pre>template&lt; class F, class A1, ..., class An &gt; handle create( pthread_attr_t const * attr, F f, A1 a1, ..., An an );
template&lt; class F, class A1, ..., class An &gt; handle create( thread_attr const &amp; attr, F f, A1 a1, ..., An an );</pre>
    <p>
        <em>Returns:</em> <code>create( attr, bind( f, a1, ..., an ) )</code>.</p>
    <pre>template&lt; class F &gt; handle create( F f );</pre>
    <p>
        <em>Returns:</em> <code>create( static_cast&lt; pthread_attr_t const * &gt;( 0 ), f
            )</code>.</p>
    <pre>template&lt; class F, class A1, ..., class An &gt; handle create( F f, A1 a1, ..., An an );</pre>
    <p>
        <em>Returns:</em> <code>create( static_cast&lt; pthread_attr_t const * &gt;( 0 ), bind(
            f, a1, ..., an ) )</code>.</p>
    <pre>handle self();</pre>
    <p>
        <em>Effects:</em> <code>pthread_attach_np( pthread_self() )</code>.</p>
    <p>
        <em>Returns:</em> a <em>handle</em> that stores <code>pthread_self()</code> as <em>pt_</em>.</p>
    <pre>int join( handle const &amp; th );</pre>
    <p>
        <em>Returns:</em> <code>pthread_join2_np( th.pt_ )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_cancel</code>.</p>
    <pre>int try_join( handle const &amp; th );</pre>
    <p>
        <em>Returns:</em> <code>pthread_tryjoin2_np( th.pt_ )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int timed_join( handle const &amp; th, timespec const &amp; abstime );</pre>
    <p>
        <em>Returns:</em> <code>pthread_timedjoin2_np( th.pt_, &amp;abstime )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_cancel</code>.</p>
    <pre>void exit();</pre>
    <p>
        <em>Effects:</em> Exits the current thread as if by calling <code>pthread_exit( 0 )</code>.</p>
    <p>
        <em>Throws:</em> <code>thread_exit( 0 )</code>.</p>
    <pre>void cancel( handle const &amp; th );</pre>
    <p>
        <em>Effects:</em> Delivers a cancel request to the thread identified by <em>th</em>
        as if by calling <code>pthread_cancel( th.pt_ )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>int set_cancel_state( int cs );</pre>
    <p>
        <em>Requires:</em> <em>cs</em> is <em>PTHREAD_CANCEL_ENABLE</em> or <em>PTHREAD_CANCEL_DISABLE</em>.</p>
    <p>
        <em>Effects:</em> Sets the cancel state of the current thread to <em>cs</em> as
        if by calling <em>pthread_setcancelstate</em>.</p>
    <p>
        <em>Returns:</em> The previous cancel state for the current thread.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>void test_cancel();</pre>
    <p>
        <em>Effects:</em> This function is a cancelation point. It has no other effects.</p>
    <p>
        <em>Throws:</em> <code>thread_cancel</code>.</p>
    <pre>class disable_cancelation
{
private: <em>// exposition only</em>

    int cs_;

public:

    disable_cancelation();
    ~disable_cancelation();
};
</pre>
    <p>
        The class disable_cancelation disables cancelations for the current scope.</p>
    <pre>disable_cancelation();</pre>
    <p>
        <em>Effects:</em> Initializes <em>cs_</em> to <code>set_cancel_state( PTHREAD_CANCEL_DISABLE
            )</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>~disable_cancelation();</pre>
    <p>
        <em>Effects:</em> <code>set_cancel_state( cs_ );</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>void sleep( timespec const &amp; reltime );</pre>
    <p>
        <em>Effects:</em> Suspends the execution of the current thread for the amount of
        time represented by <em>reltime</em>. This function is a cancelation point.</p>
    <p>
        <em>Throws:</em> <code>thread_cancel</code>.</p>
    <pre>void yield();</pre>
    <p>
        <em>Effects:</em> Equivalent to <code>sched_yield()</code>.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <pre>void yield( unsigned k );</pre>
    <p>
        <em>Effects:</em> Provides a hint to the implementation that the current thread
        has been unable to make progress for <em>k</em> iterations. For the purposes of
        this definition, an iteration typically consists of a few machine instructions,
        some of them atomic.</p>
    <p>
        <em>Throws:</em> nothing.</p>
    <p>
        [<em>Note:</em> An implementation of <em>yield</em> might do the one of the following
        based on the value of k, listed from small to large values:</p>
    <ul>
        <li>Return immediately;</li>
        <li>Switch to another hardware thread by using an yield instruction;</li>
        <li>Switch to the thread that is in the front of the scheduler "ready to run" queue;</li>
        <li>Switch to a random thread, regardless of priority, in the hope of avoiding a livelock,
            or start decreasing the dynamic priority of the current thread.</li>
    </ul>
    <p>
        <em>--end note.</em>]</p>
    <p>
        [<em>Example:</em></p>
    <pre>void acquire_spinlock( int * spinlock )
{
    for( unsigned k = 0; atomic_swap_acquire( &amp;spinlock, 1 ); ++k )
    {
        std::thread::yield( k );
    }
}
</pre>
    <p>
        <em>--end example.</em>]</p>
    <pre>unsigned concurrency();</pre>
    <p>
        <em>Returns:</em> The approximate number of non-competing threads in the current
        process that will ensure optimal load for the underlying platform.</p>
    <p>
        [<em>Note:</em> This is usually equal to the number of processing cores, but hardware
        support for symmetric multithreading or process affinity masks can affect the value.
        Successive calls may return different values. <em>--end note.</em>]</p>
    <p>
        [<em>Note:</em> This function returns a value that is not compatible with that returned
        by <em>pthread_getconcurrency</em>. <em>--end note</em>]</p>
    <h2>
        <a name="principles">III. Design Principles and Assumptions</a></h2>
    <h3>
        A. Pthreads as a C interface</h3>
    <p>
        The central assumption of this proposal is that we want a common threading infrastructure
        for C and C++, with the two interfaces just being alternative ways to get at the
        common functionality. Among other things, this would allow mixed C/C++ code to work
        reliably in the presence of multiple threads.</p>
    <p>
        It would be unrealistic for the C++ committee to innovate in the area of C threading
        interfaces, which is why the document makes the obvious decision to build on the
        existing ISO/IEC POSIX standard, which also happens to be the de-facto threading
        standard, available essentially everywhere.</p>
    <p>
        Adopting a subset of the Pthreads C binding as part of chapter 30 also allows us
        more latitude in defining the C++ API; we can leave some facilities we deem too
        advanced or less critical as only accessible via <em>&lt;pthread.h&gt;</em>. At
        the same time, the design aims to make <em>&lt;thread&gt;</em> without <em>&lt;pthread.h&gt;</em>
        sufficient for most common tasks.</p>
    <h3>
        B. Pthreads as a C++ interface</h3>
    <p>
        Given the decision to adopt Pthreads as the C interface to a common threading infrastructure,
        it makes sense for the C++ portion to represent a C++ binding to the POSIX threading
        model and not to define an incompatible model of its own.</p>
    <h3>
        C. Cancelation</h3>
    <p>
        The proposed text assumes that we want, in a few years time, to be able to freely
        use Pthreads cancelation in C++ code and C++ cancelation in C code. It also assumes
        that we want to be able to throw C++ exceptions through C code and have a mechanism
        via which the C code can release its resources as its scopes are left during the
        stack unwinding.</p>
    <h3>
        D. Expressive Power of the C++ API</h3>
    <p>
        With one exception (not providing support for a <em>void*</em> thread return value),
        the proposal conservatively places no additional constraints on the C++ side that
        aren't already present in Pthreads. In particular, the C++ API does not prohibit:</p>
    <ul>
        <li>Obtaining a fully-featured handle to the current thread and passing it to another
            thread;</li>
        <li>Canceling the current thread;</li><li>Using <em>pthread_exit</em> or <em>thread::exit</em>
            to terminate the main thread without terminating the process;</li>
        <li>Canceling the main thread;</li><li>Joining the main thread.</li></ul>
    <h2>
        <a name="decisions">IV. Design Decisions</a></h2>
    <h3>
        A. Naming</h3>
    <p>
        The proposed text uses the Pthreads names with the words separated with underscores
        for its C++ portion, consistent with its C++ binding nature.</p>
    <h3>
        B. POSIX Function Subset</h3>
    <p>
        The proposal generally aimed to include a portable subset of the POSIX functions
        that is required to implement the C++ API with most of its functions being one-liners.
        The starting point was the list of <em>pthread_*</em> functions that are described
        as always available on XSI-conformant systems, with the following subtractions:</p>
    <p>
        <em>pthread_atfork, pthread_attr_get/setstack, pthread_attr_get/setstackaddr, pthread_kill,
            pthread_sigmask, pthread_get/setconcurrency</em></p>
    <p>
        and the following additions:</p>
    <p>
        <em>pthread_*_timedlock, CLOCK_MONOTONIC, pthread_condattr_get/setclock</em></p>
    <p>
        The subtractions are either not useful in practice or were motivated by the current
        limitations of the Windows platform.</p>
    <p>
        Some of the additions (or the absence of some subtractions) may prove controversial,
        even though they are backed by extensive POSIX motivation and rationale. They are
        part of the proposed text since their absence would unfairly tip the scales in favor
        of not including them in the standard based on non-technical grounds.</p>
    <p>
        The document uses <em>struct timespec</em> for timeouts even in its C++ portion
        due to current lack of a suitable C++ type. This has necessitated the inclusion
        of <em>clock_gettime</em>, because otherwise the user would have no direct way of
        coming up with proper values for a <em>timespec</em>.</p>
    <h3>
        C. Copyable Thread Handles</h3>
    <p>
        The proposal uses the copyable handle model presented in N2090, motivated by the
        following:</p>
    <ul>
        <li>it offers a simple and straightforward programming model;</li>
        <li>the design attempts to cover all programming scenarios that can be achieved via
            a <em>pthread_t,</em> as per design principle III.D;</li>
        <li>copyable handles are hard to implement correctly and efficiently. If there is a
            choice between two facilities, only one of which can go into the standard library,
            I believe that the option that maximizes the utility of the library is to pick the
            facility that is harder for the programmers to implement.</li>
    </ul>
    <p>
        On the efficiency side, the proposed text contains suggested minimal extensions
        to the Pthreads infrastructure that enables the copyable handle to be implemented
        essentially with one-liners and little to no overhead over a <em>pthread_t</em>.
        When the suggested extensions are not available, the current prototype implementation
        emulates them, requiring less memory per thread than the N2090 prototype.</p>
    <h3>
        D. Thread Safety</h3>
    <p>
        The proposal allows concurrent operations on the same thread. This allows a portion
        of the code to observe or manipulate a thread via a handle without fear of introducing
        undefined behavior due to a data race.</p>
    <h3>
        E. Implementation Hiding</h3>
    <p>
        The proposal aims to maximize the flexibility of the implementation by not exposing
        the internal layout of the underlying data structures. This could allow a vendor
        to ship an updated implementation while still maintaining binary compatibility.</p>
    <h3>
        F. &lt;pthread.h&gt; vs &lt;cpthread&gt;</h3>
    <p>
        The proposal uses the POSIX name of the header, <em>&lt;pthread.h&gt;</em>, consistent
        with the new approach to <em>.h</em> headers that the committee seems to be adopting:
        leave the C <em>header.h</em> unmodified and provide <em>&lt;cheader&gt;</em> as
        a C++ alias.</p>
    <p>
        A <em>&lt;cpthread&gt;</em> is conservatively not proposed at the moment, but it
        can be added if deemed necessary. The current absence of <em>&lt;cpthread&gt;</em>
        reflects the intent that a C++ program should generally be able to only use <em>&lt;thread&gt;</em>
        and <em>std::</em> facilities (except in rare circumstances such as using statically
        initialized objects in an implementation file); that is, <em>&lt;thread&gt;</em>
        is intended to serve as a C++ binding to the same underlying POSIX thread support
        infrastructure.</p>
    <p>
        The proposal does not move the <em>&lt;pthread.h&gt;</em> names into namespace <em>std</em>
        because the names are allowed to be macros.</p>
    <p>
        The document specifies the full synopsis of the subset of <em>&lt;pthread.h&gt;</em>
        that is guaranteed to be provided by conforming C++ implementations, rather than
        list only the differences between it and POSIX's <em>&lt;pthread.h&gt;</em>. It's
        much easier for a programmer to just look at the synopsis to see what is available
        rather than to have to apply a mental "patch" to the correct revision of POSIX <em>&lt;pthread.h&gt;</em>
        using a "diff" in the C++ standard.</p>
    <h3>
        G. Cancelation</h3>
    <p>
        I won't rehash the endless cancelation debates here, as most of us have grown tired
        of them. I'll just say the following:</p>
    <p>
        We have an unique opportunity before us. The chance to make mixed C/C++ code possible
        to write correctly and reliably, even in the presence of multiple threads. The POSIX
        group has already done the heavy lifting for us, effectively introducing exceptions
        and destructors into C via <em>pthread_exit</em> and <em>pthread_cleanup_push</em>.
        Now we just need to acknowledge their efforts in the C++ standard.</p>
    <p>
        Despite the fact that proper exception-based cancelation is a fearsome and controversial
        topic, it has been shown that there are no insurmountable technical problems that
        stand in the way. The primary problem that precludes its adoption is lack of will.</p>
    <h2>
        <a name="implementability">V. Implementability</a></h2>
    <p>
        The three main platforms an implementation would need to support are POSIX with
        the proposed extensions, POSIX without the proposed extensions, and Windows.</p>
    <p>
        One implementation approach is to reduce each platform to the previous one in the
        list by providing an appropriate emulation layer.</p>
    <p>
        Windows can be converted into a POSIX platform by using <em>pthreads-win32</em>,
        available at <a href="http://sourceware.org/pthreads-win32/">http://sourceware.org/pthreads-win32/</a>.</p>
    <p>
        A POSIX platform not supporting the proposed extensions can be converted to one
        that does by using an emulation layer that defines a separate thread handle (called
        in the prototype implementaion <em>pthread2_t</em>) on top of the native <em>pthread_t</em>.
        A prototype implementation of such an emulation layer is available at:</p>
    <ul>
        <li><a href="http://www.pdimov.com/cpp/N2178/pthread.hpp">http://www.pdimov.com/cpp/N2178/pthread.hpp</a></li>
        <li><a href="http://www.pdimov.com/cpp/N2178/pthread2.cpp">http://www.pdimov.com/cpp/N2178/pthread2.cpp</a></li>
        <li><a href="http://www.pdimov.com/cpp/N2178/event.hpp">http://www.pdimov.com/cpp/N2178/event.hpp</a></li>
        <li><a href="http://www.pdimov.com/cpp/N2178/event.cpp">http://www.pdimov.com/cpp/N2178/event.cpp</a></li>
    </ul>
    <p>
        Finally, a POSIX platform providing the proposed extensions is sufficiently powerful
        to allow a nearly-trivial implementation of <em>&lt;thread&gt;</em>. A prototype
        is available at:</p>
    <ul>
        <li><a href="http://www.pdimov.com/cpp/N2178/thread.hpp">http://www.pdimov.com/cpp/N2178/thread.hpp</a></li>
    </ul>
    <p>
        A prototype implementation of the proposed <em>&lt;pthread.h&gt;</em> on the Windows
        platform, including a native implementation of the proposed extensions, will be
        available for the meeting.</p>
    <hr />
    <p>
        <em>Thanks to Beman Dawes, Alexander Terekhov, Ion Gaztañaga and Emil Dotchevski for
            reviewing this document.</em></p>
    <p>
        <em>--end</em></p>
</body>
</html>
