Document number | N2285=07-0145 |
Date | 2007-05-07 |
Project | Programming Language C++ |
Reference | ISO/IEC IS 14882:2003(E) |
Reply to | Pete Becker |
Roundhouse Consulting, Ltd. | |
pete@versatilecoding.com |
This paper is a revision of N1907=05-0617, A Multithreading Library for Standard C++, Revision 1. It incorporates the recommendations made in N2184=07-0044, Thread Launching for C++0x. Because of limited time, it undoubtedly does not accurately reflect the contents of the latter paper.
This paper does not propose wording for the standard. It discusses the proposed library threading model and documents C and C++ interfaces that support this model. There are ongoing discussions in the Evolution Working Group of possible core language approaches to some of the thread support features discussed here, so library support for thread-specific storage and once functions might not be needed. If the Library Working Group decides to adopt some or all of the model proposed in this paper for the C++ standard, writing the appropriate standards text will be straightforward.
A thread is a separate flow of execution within an application. On a multi-processor system threads can execute simultaneously on different processors. On a single-processor system and on a multi-processor system with fewer available processors than active threads two or more threads must share a processor. The details of switching a processor from one thread to another are handled by the operating system.
This library lets you create and control multiple threads and synchronize the sharing of data between these threads. It consists of compatible and complementary interfaces for programming in either C or C++. The C Interface is very similar to the thread support interface defined in the the Posix Standard (also known as pthreads), while the C++ Interface is very similar to the boost.threads library for C++.
When a C or C++ program begins execution it runs in a single thread, executing the main function. The program can create additional threads as needed. Each thread has its own copy of all auto variables, so auto values in one thread are independent of auto values in the other threads. Data with static storage duration is accessible to all threads, so those values are shared. However, changes to values in shared data often are not immediately visible in other threads. A multi-threaded application uses condition variables, mutexes, and once functions to coordinate the use of shared data by its threads, in order to ensure that shared data is not made inconsistent by simultaneous changes from more than one thread, that changes to shared data are visible to a thread when needed, and that a thread that needs data that is being created by another thread can be notified when that data becomes available.
Changes made by one thread to values in shared data often are not immediately visible in other threads. For example, on a system with two separate processors and two threads running on the two processors, if the two processors simply share main memory an attempt by one processor to write data while the other processor reads the same data could result in the second processor reading a data value that has only been partially changed by the other processor. In order to avoid this inconsistency one processor has to lock the other one out until it finishes. This locking is usually done through the hardware and is known as a bus lock. Bus locks are unavoidable, but they slow the processors down. To minimize the effect of this slowdown, multi-processor systems have separate cache memory for each processor. This cache memory holds a copy of some of the data in main memory. When a processor writes data it writes to the cache. Sometime later the changes made to the cache are written to main memory. Because of this delay, the processors could each have a different value for a data item in their caches, and those values could be different from the value in main memory.
There are three times at which changes made to memory by one thread are guaranteed to be visible in another thread:
In practice this means that:
Note, however, that locking a mutex to prevent modification of shared data while it is being read also prevents other threads from locking the mutex in order to read the data. Such critical sections should be kept as short as possible to avoid blocking other threads any longer than necessary.
A condition variable is used by a thread to wait until another thread notifies it that a condition has become true. Code that waits for a condition variable must also use a mutex; before calling any of the functions that wait for the condition variable the calling thread must lock the mutex, and when the called function returns the mutex will be locked. During the time that a thread is blocked waiting for the condition to become true the mutex is not locked.
Spurious wakeups occur when threads waiting for condition variables become unblocked without appropriate notifications. Code that waits for a condition to become true should explicitly check that condition when returning from a wait function to recognize such spurious wakeups. This is usually done with a loop:
while (condition is false) wait for condition variable;
The condition variable functions use a mutex internally; when a thread returns from a wait function any changes made to memory by threads that called a wait function or a notify function before the return will be visible to the caller.
A mutex is used to insure that only one thread executes a region of code, known as a critical section, at any one time. On entry into the critical section the code locks the mutex; if no other thread holds the mutex the lock operation succeeds and the calling thread holds the mutex. On exit from the critical section the code unlocks the mutex. If another thread holds the mutex when a thread tries to lock it the thread that tried to lock the mutex blocks until the mutex is unlocked. When more than one thread is blocked waiting for the mutex an unlock releases one of the blocked threads.
A mutex can be recursive or non-recursive. When a thread that already holds a recursive mutex attempts to lock it again the thread does not block. The thread must unlock the mutex as many times as it locked it before any other thread will be permitted to lock the mutex. When a thread that already holds a non-recursive mutex attempts to lock it again the thread will block. Since the thread cannot then unlock the mutex, the result is a deadlock. Non-recursive mutexes are usually smaller and faster than recursive mutexes, so a properly written program that uses non-recursive mutexes can be faster than one that uses recursive mutexes.
A mutex supports test and return if it provides a lock call that does not block if the mutex is already locked. Such a lock call returns a value that indicates whether the mutex was locked as a result of the call.
A mutex supports timeout if it provides a lock call that blocks until no later than a specified time waiting for the mutex to be unlocked. Such a lock call returns a value that indicates whether the mutex was locked as a result of the call.
A once function is a function that should only be called once during a program's execution. Once functions are typically used to initialize data that is shared between threads: the first thread that needs the data initializes it by calling the once function, and later threads that need the data do not call the once function. Each once function should have an associated once flag, statically initialized to indicate that the function has not been called. Code that needs to insure that the once function has been called calls call_once, passing the flag and the address of the once function. The code in call_once atomically checks the flag, and if the flag indicates that the function has not been called, calls the once function and sets the flag to indicate that the function has been called.
The function call_once uses a mutex internally; when it returns any changes made to memory by the once function will be visible to the caller.
Thread-specific storage is global data that can hold a distinct value for each thread that uses it. This permits functions executing in a single thread to share data without interfering with the data shared by the same functions when executing in other threads.
Every program begins execution in its main thread. A new thread can be started from any thread by creating an object of type thread, passing a callable object exec to the thread’s constructor. The new thread will begin execution by a call to exec(). Various operations that affect the state of the thread can be done through member functions called on the thread object.
A thread object can be moved to another thread object, but it can’t be copied. This means that there can never be more than one thread object that manages a particular thread.
A thread can be detached from its thread object thr by calling thr.detach(). After this call, thr no longer manages the thread that it used to manage (and, since thr was the only thread object that managed the thread, there is now no thread object that manages the thread). When the thread terminates, it is the responsibility of the underlying threading system to clean up any resources allocated to the thread.
A thread can be joined if it has not been detached and it has not previously been joined. When a thread joins another thread, the joining thread will block until the joined thread terminates.
A thread can be cancelled by throwing an exception object of type thread_canceled or of a type derived from thread_canceled. A handler for this exception is not required to rethrow it. Thus, cancellation can be canceled.
A program can request that a thread be cancelled by calling cancel() on the thread object that manages the target thread. Calling cancel() notifies the target thread that cancellation has been requested. It does not force cancellation to occur.
A thread can check whether another thread has requested that it be cancelled by calling cancellation_requested().
A thread can disable cancellation by creating an object of type disable_cancellation. When the object is destroyed, its destructor enables cancellation if cancellation was enabled when the object was constructed.
A thread can temporarily restore its cancellation state by creating an object of type restore_cancellation. The object's constructor takes an object of type disable_cancellation, and sets the thread's cancellation state to the state it was in at the time that the argument was constructed. The destructor of the restore_cancellation object returns the thread's cancellation state to the state it was in when that object was constructed.
When a thread calls a function that is a cancellation point, if cancellation is not disabled in that thread and a request for cancellation has been made to that thread and that request has not been handled, the thread will be cancelled. The following functions are cancellation points:
The application's main thread starts in a non-cancellable state. Consequently, no combination of disable_cancellation and restore_cancellation objects can put it into a cancellable state. Since it has no associated thread object, no other thread can request cancellation of the main thread.
C++ condition variables, mutexes, thread-specific pointers, and thread objects all have a member function named c_handle that returns an object of the corresponding C type (cnd_t, mtx_t, tss_t, and thrd_t). Each of those C++ types also has a constructor that takes an argument of the corresponding C type. [need to sort out move/copy semantics for the four underlying types]
Most of the functions return a value of type int that indicates whether the function succeeded. The values are as follows:
Use the functions and types with the prefix thrd_ to manage threads. Each thread has an identifier of type thrd_t, which is passed as an argument to the functions that manage specific threads. Each thread begins execution in a function of type thrd_start_t. To create a new thread call the function thrd_create with the address of the thread identifier, the address of the thread function, and an argument to be passed to the thread function. The thread ends when it returns from the thread function or when it calls thrd_exit. For convenience, a thread can provide a result code of type int when it ends, either by returning the code from the thread function or by passing the code to thrd_exit. To block a thread until another thread ends call thrd_join, passing the identifier of the thread to wait for and, optionally, the address of a variable of type int where the result code will be stored. To properly clean up resources allocated by the operating system, an application should call either thrd_join or thrd_detach once for each thread created by thrd_create.
Two functions operate on the current thread; they do not take a thread identifier argument. Use thrd_sleep to suspend execution of the current thread until a particular time. Use thrd_yield to request that other threads be allowed to run even if the current thread would ordinarily continue to run.
Two functions operate on thread identifiers. Use thrd_equal to determine whether two thread identifiers refer to the same thread. Use thrd_current to get a thread identifier that refers to the current thread.
Use the functions and type with the prefix cnd_ to manage condition variables. Each condition variable has an identifier of type cnd_t, which is passed as an argument to the functions that manage condition variables. Use cnd_init to create a condition variable and cnd_destroy to release any resources associated with a condition variable when it is no longer needed. To wait for a condition variable to be signalled call cnd_wait or cnd_timedwait. To unblock threads waiting for a condition variable call cnd_signal or cnd_broadcast.
Use the functions and type with the prefix mtx_ to manage mutexes. Each mutex has an identifier of type mtx_t, which is passed as an argument to the functions that manage mutexes. Use mtx_init to create a mutex and mtx_destroy to release any resources associated with a mutex when it is no longer needed. To lock a mutex call mtx_lock, mtx_timedlock or mtx_trylock. To unlock a mutex call mtx_unlock.
Use a value of type once_flag, initialized to the value ONCE_FLAG_INIT, to ensure that a function is called exactly once by passing a function pointer and the address of the once_flag object to call_once.
Use the functions and types with the prefix tss_ to manage thread-specific storage. Each thread-specific storage pointer has an identifier of type tss_t, which is passed as an argument to the functions that manage thread-specific storage. Call tss_create to create a thread-specific storage pointer and tss_delete to release any resources associated with a thread-specific storage pointer when it is no longer needed. To get the value held by the pointer in the current thread call tss_get. To change the value held by the pointer in the current thread call tss_set.
Each thread-specific storage pointer may have an associated destructor, specified in the call to tss_create. The destructor will be called when a thread terminates and the value of the pointer associated with that thread is not 0. The value of the pointer for that thread is set to 0 before calling the destructor and the old value is passed to the destructor. Since a destructor can store non-0 values in thread-specific storage pointers, this process will be repeated until no pointers for the terminating thread hold non-0 values or until a system-specific maximum number of iterations TSS_DTOR_ITERATIONS has been made.
/* ERROR REPORTING */ enum { thrd_success = ....., thrd_nomem = ....., thrd_timedout = ....., thrd_busy = ....., thrd_error = ..... }; /* THREADS */ typedef o-type thrd_t; typedef int (*thrd_start_t)(void*); int thrd_create(thrd_t *, thrd_start_t, void*); int thrd_detach(thrd_t); void thrd_exit(int); int thrd_join(thrd_t, int*); void thrd_sleep(const xtime*); void thrd_yield(void); int thrd_equal(thrd_t, thrd_t); thrd_t thrd_current(void); /* MUTEXES */ typedef o-type mtx_t; enum { mtx_plain = ....., mtx_try = ....., mtx_timed = ....., mtx_recursive = ..... }; int mtx_init(mtx_t*, int); void mtx_destroy(mtx_t*); int mtx_lock(mtx_t*); int mtx_trylock(mtx_t*); int mtx_timedlock(mtx_t*, const xtime*); int mtx_unlock(mtx_t*); /* CONDITION VARIABLES */ typedef o_type cnd_t ; int cnd_init(cnd_t*); void cnd_destroy(cnd_t*); int cnd_wait(cnd_t*, mtx_t*); int cnd_timedwait(cnd_t*, mtx_t*, const xtime*); int cnd_signal(cnd_t*); int cnd_broadcast(cnd_t*); /* THREAD-SPECIFIC STORAGE */ typedef i-type tss_t; typedef void (*tss_dtor_t)(void*); int tss_create(tss_t*, tss_dtor_t); int tss_delete(tss_t); int tss_set(tss_t, void*); void *tss_get(tss_t); #define TSS_DTOR_ITERATIONS <integer constant expression> /* ONCE FUNCTIONS */ typedef o-type once_flag; #define ONCE_FLAG_INIT <object initializer> void call_once(once_flag*, void (*)(void)); /* TIME SUPPORT */ typedef o-type xtime; enum { TIME_UTC = <integer constant expression> }; int xtime_get(xtime *, int);
int cnd_broadcast(cnd_t *cond);
Requires the usual return value.
The function unblocks all of the threads that are blocked on the condition variable *cond at the time of the call. If no threads are blocked on the condition variable at the time of the call the function does nothing.
void cnd_destroy(cnd_t *cond);
Requires no threads are blocked waiting for *cond.
The function releases any resources used by the condition variable *cond.
int cnd_init(cnd_t *cond);
Returns the usual return value.
The function creates a condition variable. If it succeeds it sets *cond to a value that uniquely identifies the newly created condition variable. A thread that calls cnd_wait on a newly created condition variable will block.
int cnd_signal(cnd_t *cond);
Returns the usual return value.
The function unblocks one of the threads that is blocked on the condition variable *cond at the time of the call. If no threads are blocked on the condition variable at the time of the call the function does nothing.
typedef o-type cnd_t;
The type is an object type o-type that holds an identifier for a condition variable.
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt);
Requires the mutex *mtx must be locked by the calling thread
Returns the usual return value.
The function atomically unlocks the mutex *mtx and blocks until the condition variable *cond is signaled by a call to cnd_signal or to cnd_broadcast, or until after the time specified by the xtime object *xt. When the calling thread becomes unblocked it locks *mtx before it returns.
int cnd_wait(cnd_t *cond, mtx_t *mtx);
Requires the mutex *mtx must be locked by the calling thread
Returns the usual return value.
The function atomically unlocks the mutex *mtx and blocks until the condition variable *cond is signaled by a call to cnd_signal or to cnd_broadcast. When the calling thread becomes unblocked it locks *mtx before it returns.
void mtx_destroy(mtx_t *mtx);
Requires no threads are blocked waiting for *mtx.
The function releases any resources used by the mutex *mtx.
int mtx_init(mtx_t *mtx, int type);
Returns the usual return value.
The function creates a mutex object with properties indicated by type, which must have one of the six values
If it succeeds it sets *mtx to a value that uniquely identifies the newly created mutex.
int mtx_lock(mtx_t *mtx);
Requires if the mutex is non-recursive it must not be locked by the calling thread.
Returns the usual return value.
The function blocks until it locks the mutex *mtx.
enum { mtx_plain = ..... };
The compile-time constant is passed to mtx_init to create a mutex object that supports neither timeout nor test and return.
enum { mtx_recursive = ..... };
The compile-time constant is passed to mtx_init to create a mutex object that supports recursive locking.
typedef o-type mtx_t;
The type is an object type o-type that holds an identifier for a mutex.
enum { mtx_timed = ..... };
The compile-time constant is passed to mtx_init to create a mutex object that supports timeout.
int mtx_timedlock(mtx_t *mtx, const xtime *xt);
Requires the mutex *mtx must be of type mtx_timed or of type mtx_timed | mtx_recursive.
Returns the usual return value.
The function blocks until it locks the mutex *mtx or until the time specified by the xtime object *xt.
enum { mtx_try = ..... };
The compile-time constant is passed to mtx_init to create a mutex object that supports test and return.
int mtx_trylock(mtx_t *mtx);
Requires the mutex *mtx must be of type mtx_try, of type mtx_try | mtx_recursive, of type mtx_timed, or of type mtx_timed | mtx_recursive.
Returns the usual return value.
The function attempts to lock the mutex *mtx. If the mutex is already locked the function returns without blocking.
int mtx_unlock(mtx_t *mtx);
Requires the mutex *mtx must be locked by the calling thread.
Returns the usual return value.
The function unlocks the mutex *mtx.
enum { thrd_busy = ..... };
The compile-time constant is returned by a function to indicate that the requested operation failed because a resource requested by a test and return function is already in use.
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
Returns the usual return value.
The function creates a new thread executing func(arg). If it succeeds it sets *thr to a value that uniquely identifies the newly created thread. The function does not return until the new thread has begun execution.
thrd_t thrd_current(void);
The function returns a value that uniquely identifies the thread that called it.
int thrd_detach(thrd_t thr);
Requires the application must not have previously called thrd_detach or thrd_join for the thread identified by thr.
Returns the usual return value.
The function tells the operating system to dispose of any resources allocated to the thread identified by thr when that thread terminates.
int thrd_equal(thrd_t thr0, thrd_t thr1);
The function returns zero if thr0 and thr1 refer to different threads. Otherwise it returns a non-zero value.
enum { thrd_error = ..... };
The compile-time constant is returned by a function to indicate that the requested operation failed.
void thrd_exit(int res);
The function terminates execution of the calling thread and sets its result code to res.
int thrd_join(thrd_t thr, int *res);
Requires the application must not have previously called thrd_join or thrd_detach for the thread identified by thr.
Returns the usual return value.
The function tells the operating system to dispose of any resources allocated to the thread identified by thr when that thread terminates and blocks until that thread has terminated. If res is not a null pointer it stores the thread's result code in *res.
enum { thrd_nomem = ..... };
The compile-time constant is returned by a function to indicate that the requested operation failed because it was unable to allocate memory.
void thrd_sleep(const xtime *xt);
The function suspends execution of the calling thread until after the time specified by the xtime object *xt.
typedef int (*thrd_start_t)(void*);
The type is the function type that is passed to thrd_create to create a new thread.
enum { thrd_success = ..... };
The compile-time constant is returned by a function to indicate that the requested operation succeeded.
typedef o-type thrd_t;
The type is an object type o-type that holds an identifier for a thread.
enum { thrd_timedout = ..... };
The compile-time constant is returned by a timed wait function to indicate that the time specified in the call was reached without acquiring the requested resource.
void thrd_yield(void);
The function permits other threads to run even if the current thread would ordinarily continue to run.
enum { TIME_UTC = <integer constant expression> };
The compile-time constant is a non-zero value that designates Coordinated Universal Time (UTC) as the time base for the values set by xtime_get.
int tss_create(tss_t *key, tss_dtor_t dtor);
Returns the usual return value.
The function creates a thread-specific storage pointer with destructor dtor, which may be null. If it succeeds it sets *key to a value that uniquely identifies the newly created pointer.
#define TSS_DTOR_ITERATIONS <integer constant expression>
The macro yields the maximum number of times that destructors will be called when a thread terminates.
typedef void (*tss_dtor_t)(void*);
The type is the function type for a destructor for a thread-specific storage pointer.
void tss_delete(tss_t key);
The function releases any resources used by the thread-specific storage pointer key.
void *tss_get(tss_t key);
The function returns the value for the current thread held in the thread-specific storage pointer identified by key.
int tss_set(tss_t key, void *val);
Returns the usual return value.
The function sets the value for the current thread held in the thread-specific storage pointer identified by key to val.
typedef o-type tss_t;
The type is an object type o-type that holds an identifier for a thread-specific storage pointer.
typedef struct {
int sec; /* seconds since 1 Jan. 1970 00:00:00 */
int nsec; /* nanoseconds since time specified by sec */
} xtime;
The struct xtime contains members that describe times with nanosecond resolution. The comment following each member desribes its meaning.
int xtime_get(xtime *xt, int base);
The function sets the xtime object pointed to by xt to hold the current time based on the time base base. If successful it returns the non-zero value base, which must be TIME_UTC; otherwise it returns 0.
namespace std { /* ERROR REPORTING */ class lock_error; class thread_resource_error; /* THREADS */ class thread; class thread_canceled; class thread_group; /* MUTEXES */ class mutex; class try_mutex; class timed_mutex; class recursive_mutex; class recursive_try_mutex; class recursive_timed_mutex; /* CONDITION VARIABLES */ class condition; /* THREAD-SPECIFIC STORAGE */ class thread_specific_ptr; /* ONCE FUNCTIONS */ typedef o-type once_flag; #define ONCE_FLAG_INIT = ..... const once_flag once_init = .....; void call_once(void (*func)(void), once_flag& flag); // C++ Only void call_once(once_flag *flag, void (*func)(void)); /* THREAD ID COMPARISONS */ bool operator==(const thread::id&, const thread::id&); bool operator!=(const thread::id&, const thread::id&); /* CURRENT THREAD OPERATIONS */ namespace this_thread { thread::id get_id(); void sleep(const xtime&); void yield(); class disable_cancellation; class restore_cancellation; void cancellation_point(); bool cancellation_enabled(); bool cancellation_requested(); } // namespace this_thread } // namespace std /* C INTERFACE TYPES */ typedef unspecified cnd_t; typedef unspecified mtx_t; typedef unspecified thrd_t; typedef unspecified tss_t;
void call_once(void (*func)(void), once_flag& flag); // C++ Only void call_once(once_flag *pflag, void (*func)(void));
The functions use flag and *pflag to ensure that func is called exactly once.
bool cancellation_enabled();
The function returns true if cancellation is enabled in the calling thread, otherwise false.
void cancellation_point();
If cancellation is enabled in the calling thread and there is an unhandled cancellation request to the calling thread, the function handles the cancellation request by throwing an object of type thread_canceled, otherwise it does nothing.
bool cancellation_requested();
The function returns true if there is an unhandled cancellation request to the calling thread, otherwise false.
class condition { public: condition(); condition(cnd_t); ~condition(); template <class Lock> void wait(Lock& lock); template <class Lock, class Pred> void wait(Lock& lock, Pred pred); template <class Lock> bool timed_wait(Lock& lock, const xtime& xt); template <class Lock, class Pred> bool timed_wait(Lock& lock, const xtime& xt, Pred pred); void notify_one(); void notify_all(); typedef unspecified native_condition_handle; native_condition_handle native_handle() const; cnd_t c_handle() const; // exposition only private: // not implemented condition(const condition&); condition& operator=(const condition&); };
The class describes an object that manages a condition variable. Use wait or timed_wait to wait for a condition to become true. Use notify_one to notify one waiting thread that the condition has become true and notify_all to notify all waiting threads that the condition has become true. Objects of class condition cannot be copied.
cnd_t c_handle() const;
The member function returns an object of type cnd_t that can be passed to functions in the C interface for operations on this condition variable.
condition(); condition(cnd_t cnd);
The first constructor constructs a condition object; a thread that calls wait on a newly constructed condition object will block. The second constructor constructs a condition object with the same state as cnd.
~condition();
Requires no threads are blocked waiting for the condition object.
The destructor releases any resources used by the condition object.
native_condition_handle native_handle() const;
The member function returns an object that can be passed to an implementation-defined set of system functions for operations on the condition variable managed by this object.
typedef unspecified native_condition_handle;
The typedef names a type for objects that can be passed to an implementation-defined set of system functions for operations on the thread managed by this object.
void notify_one();
The member function unblocks one of the threads that is blocked on the condition object at the time of the call. If no threads are blocked on the object at the time of the call the function does nothing.
void notify_all();
The member function unblocks all of the threads that are blocked on the condition object at the time of the call. If no threads are blocked on the object at the time of the call the function does nothing.
template <class Lock> bool timed_wait(Lock& lock, const xtime& xt); template <class Lock, class Pred> bool timed_wait(Lock& lock, const xtime& xt, Pred pred);
Throws an object of class lock_error if the lock object lock is not locked.
The first member function atomically unlocks lock and blocks until the condition object is signaled by a call to notify_one or to notify_all, or until after the time specified by the xtime object xt. When the calling thread becomes unblocked it locks the lock object lock before it returns. The function returns false if it returned because the time xt had passed, otherwise it returns true.
The second member function atomically unlocks lock and blocks until the condition object is signaled by a call to notify_one or to notify_all and the predicate pred() returns true (that is, the function incorporates the loop that is needed to avoid spurious wakeups), or until after the time specified by the xtime object xt. When the calling thread becomes unblocked it locks the lock object lock before it returns. The function returns false if it returned because the time xt had passed, otherwise it returns true.
template <class Lock> void wait(Lock& lock); template <class Lock, class Pred> void wait(Lock& lock, Pred pred);
Throws an object of class lock_error if the lock object lock is not locked.
The first member function atomically unlocks lock and blocks until the condition object is signaled by a call to notify_one or to notify_all. When the calling thread becomes unblocked it locks the lock object lock before it returns.
The second member function atomically unlocks lock and blocks until the condition object is signaled by a call to notify_one or to notify_all and the predicate pred() returns true (that is, the function incorporates the loop that is needed to avoid spurious wakeups). When the calling thread becomes unblocked it locks the lock object lock before it returns.
class disable_cancellation { public: disable_cancellation(); ~disable_cancellation(); // exposition only private: // not implemented disable_cancellation(const disable_cancellation&); disable_cancellation& operator= (const disable_cancellation&); };
The class describes an object that can be created to disable cancellation throughout its lifetime.
disable_cancellation();
The constructor disables cancellation in the calling thread.
~disable_cancellation();
The destructor enables cancellation in the calling thread only if cancellation was enabled in the calling thread when this disable_cancellation object was created.
class restore_cancellation { public: restore_cancellation(disable_cancellation&); ~restore_cancellation(); // exposition only private: // not implemented restore_cancellation(const restore_cancellation& rc); restore_cancellation& operator= (const restore_cancellation&); };
The class describes an object that can be created to restore cancellation, throughout its lifetime, to the state prior to creation of rc.
restore_cancellation(disable_cancellation& d);
The constructor enables cancellation in the calling thread only if the desctructor of the disable_cancellation object d would enable cancellation in the calling thread.
~restore_cancellation();
The destructor disables cancellation in the calling thread only if cancellation was disabled in the calling thread when this restore_cancellation object was created.
thread::id get_id();
The function returns an object that uniquely identifies the calling thread.
class lock_error
: public std::runtime_error
{
public:
lock_error();
};
The class describes an exception thrown to indicate that an attempted operation involving a lock failed because the lock was not in a required state.
typedef o-type once_flag;
The type describes a data object for use as the first argument to call_once.
#define ONCE_FLAG_INIT <object initializer>
The macro yields a value that can be used to initialize an object of type once_flag.
const once_flag once_init = .....;
The object provides an initial value for objects of type once_flag.
class mutex { public: mutex(); mutex(mtx_t); ~mutex(); typedef SL0 scoped_lock; typedef unspecified native_mutex_handle; native_thread_handle native_handle() const; mtx_t c_handle() const; // exposition only private: // not implemented mutex(const mutex&); mutex& operator= (const mutex&); };
The class describes an object that can be used with a scoped lock to provide a non-recursive mutex. Objects of class mutex cannot be copied.
mtx_t c_handle();
The member function returns an object of type mtx_t that can be passed to functions in the C interface for operations on this mutex.
mutex(); mutex(mtx_t mtx);
The first constructor constructs a mutex in the unlocked state. The second constructor constructs a mutex in the same state as mtx.
~mutex();
Requires the object must not be locked.
The destructor releases any resources used by the object.
native_mutex_handle native_handle() const;
The member function returns an object that can be passed to an implementation-defined set of system functions for operations on the mutex managed by this object.
typedef unspecified native_mutex_handle;
The typedef names a type for objects that can be passed to an implementation-defined set of system functions for operations on the thread managed by this object.
class recursive_mutex { public: recursive_mutex(); recursive_mutex(mtx_t); ~recursive_mutex(); typedef SL0 scoped_lock; typedef unspecified native_recursive_mutex_handle; native_recursive_mutex_handle native_handle() const; mtx_t c_handle() const; // exposition only private: // not implemented recursive_mutex(const recursive_mutex&); recursive_mutex& operator= (const recursive_mutex&); };
The class describes an object that can be used with a lock object to provide a recursive mutex object. Objects of class recursive_mutex cannot be copied.
mtx_t c_handle() const;
The member function returns an object of type mtx_t that can be passed to functions in the C interface for operations on this mutex.
native_recursive_mutex_handle native_handle() const;
The member function returns an object that can be passed to an implementation-defined set of system functions for operations on the mutex managed by this object.
typedef unspecified native_recursive_mutex_handle;
The typedef names a type for objects that can be passed to an implementation-defined set of system functions for operations on the thread managed by this object.
recursive_mutex(); recursive_mutex(mtx_t mtx);
The first constructor constructs a recursive_mutex in the unlocked state. The second constructor constructs a recursive_mutex in the same state as mtx.
~recursive_mutex();
Requires the object must not be locked.
The destructor releases any resources used by the object.
class recursive_timed_mutex { public: recursive_timed_mutex(); recursive_timed_mutex(mtx_t); ~recursive_timed_mutex(); typedef SL0 scoped_lock; typedef SL1 scoped_try_lock; typedef SL2 scoped_timed_lock; typedef unspecified native_recursive_timed_mutex_handle; native_thread_handle native_handle() const; mtx_t c_handle() const; // exposition only private: // not implemented recursive_timed_mutex(const recursive_timed_mutex&); recursive_timed_mutex& operator= (const recursive_timed_mutex&); };
The class describes an object that can be used with a scoped lock, a scoped try lock or a scoped timed lock to provide a recursive mutex object that supports test and return and timeout. Objects of class recursive_timed_mutex cannot be copied.
mtx_t c_handle() const;
The member function returns an object of type mtx_t that can be passed to functions in the C interface for operations on this mutex.
native_recursive_timed_mutex_handle native_handle() const;
The member function returns an object that can be passed to an implementation-defined set of system functions for operations on the mutex managed by this object.
typedef unspecified native_recursive_timed_mutex_handle;
The typedef names a type for objects that can be passed to an implementation-defined set of system functions for operations on the mutex managed by this object.
recursive_timed_mutex(mtx_t mtx); recursive_timed_mutex();
The first constructor constructs a recursive_timed_mutex in the unlocked state. The second constructor constructs a recursive_timed_mutex in the same state as mtx.
~recursive_timed_mutex();
Requires the object must not be locked.
The destructor releases any resources used by the object.
class recursive_try_mutex { public: recursive_try_mutex(); recursive_try_mutex(mtx_t); ~recursive_try_mutex(); typedef SL0 scoped_lock; typedef SL1 scoped_try_lock; typedef unspecified native_recursive_try_mutex_handle; native_thread_handle native_handle() const; mtx_t c_handle() const; // exposition only private: // not implemented recursive_try_mutex(const recursive_try_mutex&); recursive_try_mutex& operator= (const recursive_try_mutex&); };
The class describes an object that can be used with a scoped lock or a scoped_try_lock to provide a recursive mutex object that supports test and return. Objects of class recursive_try_mutex cannot be copied.
mtx_t c_handle() const;
The member function returns an object of type mtx_t that can be passed to functions in the C interface for operations on this mutex.
native_recursive_try_mutex_handle native_handle() const;
The member function returns an object that can be passed to an implementation-defined set of system functions for operations on the mutex managed by this object.
typedef unspecified native_recursive_try_mutex_handle;
The typedef names a type for objects that can be passed to an implementation-defined set of system functions for operations on the mutex managed by this object.
recursive_try_mutex(); recursive_try_mutex(mtx_t mtx);
The first constructor constructs a recursive_try_mutex in the unlocked state. The second constructor constructs a recursive_try_mutex in the same state as mtx.
~recursive_try_mutex();
Requires the object must not be locked.
The destructor releases any resources used by the object.
Every mutual exclusion class mtx defines a nested type mtx::scoped_lock that can be used to create a lock object for an object of the type mtx.
A lock object is an object whose constructor locks an associated mutex object and whose destructor unlocks the mutex object. Thus, unlocking is guaranteed in the presence of exceptions. Lock objects cannot be copied.
class mtx::scoped_lock { public: typedef mtx mutex_type; scoped_lock(mtx& m); scoped_lock(mtx& m, bool lck); ~scoped_lock(); operator const void *() const; bool locked() const; void lock(); void unlock(); // exposition only private: mtx& mm; bool is_locked; // not implemented scoped_lock::scoped_lock(const scoped_lock&); scoped_lock& scoped_lock::operator= (const scoped_lock&); };
void lock();
The member function locks the stored mutual exclusion object mm and sets the stored value is_locked to true.
bool locked() const;
The member function returns the stored value is_locked.
typedef mtx mutex_type;
The nested type is a synonym for the containing type mtx.
operator const void *() const;
The member function returns 0 if the stored value is_locked is false, otherwise a non-0 pointer value.
scoped_lock(mtx& m); scoped_lock(mtx& m, bool lck);
The first constructor constructs a scoped_lock object with stored value mm set to m and then calls lock.
The second constructor constructs a scoped_lock object with stored value mm set to m. If lck is true the constructor calls lock. Otherwise the stored value is_locked is set to false.
~scoped_lock();
The destructor calls unlock if the stored value is_locked is true. Otherwise the destructor does nothing.
void unlock();
The member function unlocks the stored mutual exclusion object mm and sets the stored value is_locked to false. Note that if mm is a recursive mutex unlocking mm doesn't necessarily put mm into the unlocked state.
A mutual exclusion class mtx that supports timeout defines a nested type mtx::scoped_timed_lock that can be used to create a lock object for an object of the type mtx.
class mtx::scoped_timed_lock { public: typedef mtx mutex_type; scoped_timed_lock(mtx& m, const xtime& xt); scoped_timed_lock(mtx& m, bool lck); ~scoped_timed_lock(); operator const void *() const; bool locked() const; void lock(); bool timed_lock(const xtime& xt); void unlock(); // exposition only private: mtx& mm; bool is_locked; // not implemented scoped_timed_lock::scoped_timed_lock(const scoped_timed_lock&); scoped_timed_lock& scoped_timed_lock::operator= (const scoped_timed_lock&); };
void lock();
The member function locks the stored mutual exclusion object mm and sets the stored value is_locked to true.
bool locked() const;
The member function returns the stored value is_locked.
typedef mtx mutex_type;
The nested type is a synonym for the containing type mtx.
operator const void *() const;
The member function returns 0 if the stored value is_locked is false, otherwise a non-0 pointer value.
scoped_timed_lock(mtx& m, const xtime& xt); scoped_timed_lock(mtx& m, bool lck);
The first constructor constructs a scoped_timed_lock object with stored value mm set to m, then calls timed_lock(xt).
The second constructor constructs a scoped_timed_lock object with stored value mm set to m. If lck is true the constructor calls lock. Otherwise the stored value is_locked is set to false.
~scoped_timed_lock();
The destructor calls unlock if the stored value is_locked is true. Otherwise the destructor does nothing.
bool timed_lock(const xtime& xt);
The member function attempts to lock the stored mutual exclusion object mm, using its timeout mechanism to avoid blocking beyond the time specified by the xtime object xt, sets the stored value is_locked to true if the lock attempt was successful or false if it was not usccessful, and returns the stored value is_locked.
void unlock();
The member function unlocks the stored mutual exclusion object mm and sets the stored value is_locked to false. Note that if mm is a recursive mutex unlocking mm doesn't necessarily put mm into the unlocked state.
A mutual exclusion class mtx that supports test and return defines a nested type mtx::scoped_try_lock that can be used to create a lock object for an object of the type mtx.
class mtx::scoped_try_lock { public: typedef mtx mutex_type; scoped_try_lock(mtx& m); scoped_try_lock(mtx& m, bool lck); ~scoped_try_lock(); operator const void *() const; bool locked() const; void lock(); bool try_lock(); void unlock(); // exposition only private: mtx& mm; bool is_locked; // not implemented scoped_try_lock::scoped_try_lock(const scoped_try_lock&); scoped_try_lock& scoped_try_lock::operator= (const scoped_try_lock&); };
void lock();
The member function locks the stored mutual exclusion object mm and sets the stored value is_locked to true.
bool locked() const;
The member function returns the stored value is_locked.
typedef mtx mutex_type;
The nested type is a synonym for the containing type mtx.
operator const void *() const;
The member function returns 0 if the stored value is_locked is false, otherwise a non-0 pointer value.
scoped_try_lock(mtx& m); scoped_try_lock(mtx& m, bool lck);
The first constructor constructs a scoped_try_lock object with stored value mm set to m, then calls try_lock.
The second constructor constructs a scoped_try_lock object with stored value mm set to m. If lck is true the constructor calls lock. Otherwise the stored value is_locked is set to false.
~scoped_try_lock();
The destructor calls unlock if the stored value is_locked is true. Otherwise the destructor does nothing.
bool try_lock();
The member function attempts to lock the stored mutual exclusion object mm, using its test and return mechanism, sets the stored value is_locked to true if the lock attempt was successful or false if it was not successful, and returns the stored value is_locked.
void unlock();
The member function unlocks the stored mutual exclusion object mm and sets the stored value is_locked to false. Note that if mm is a recursive mutex unlocking mm doesn't necessarily put mm into the unlocked state.
void sleep(const xtime& xt);
The function blocks the calling thread at least until the time specified by the xtime object xt.
class thread { public: thread(); template <class Func> explicit thread(Func func); thread(thread&&); thread(thrd_t); ~thread(); thread& operator=(thread&&); void swap(thread&); void detach(); void join(); void operator()(); bool joinable() const; void cancel(); bool cancellation_requested() const; class id { public: id() throw(); }; id get_id() const; typedef unspecified native_thread_handle; native_thread_handle native_handle() const; thrd_t c_handle() const; static unsigned hardware_concurrency(); // exposition only private: // not implemented thread(const thread&); thread& operator= (const thread&); };
The class thread describes an object for observing the state of a thread (join) and managing the state of the current Objects of class thread cannot be copied.
A thread object is joinable if the application has not made a call to thread::join for that object, has not made a call to thread::detach for that object, and has not made a call to thread_group::join_all for a thread_group object observing that thread object.
thrd_t c_handle() const;
The member function returns an object of type thrd_t that can be passed to functions in the C interface for operations on this thread object.
void cancel();
The member function makes a cancellation request for the thread controlled by this thread object.
bool cancellation_requested() const;
The member function returns true if there is an unhandled cancellation request for the thread controlled by this thread object.
void detach();
The member function detaches the thread object from the thread that it manages. After the call, the thread does not manage any object.
thread::id get_id();
The member function returns an object that uniquely identifies the thread managed by this thread object if that thread has not been detached; otherwise it returns id().
unsigned thread::hardware_concurrency() throw();
The static member function returns a measure of the number of threads which could possibly execute concurrently. On platforms where this value cannot be computed or is not well defined the function should return 1.
void join(); void operator()();
Requires the object must be joinable.
The member functions mark this thread object as non-joinable then block until the thread observed by this thread object terminates.
bool joinable() const;
The member function returns true only if this thread object is joinable.
native_thread_handle native_handle() const;
The member function returns an object that can be passed to an implementation-defined set of system functions for operations on the thread managed by this object.
typedef unspecified native_thread_handle;
The typedef names a type for objects that can be passed to an implementation-defined set of system functions for operations on the thread managed by this object.
thread& operator= (thread&& other);
The member operator copies the state of other into *this and leaves other in a default-constructed state.
void swap(thread& other);
Swaps the state of *this and other.
thread(); template<class Func> explicit thread(Func func); thread(thread&& other); thread(thrd_t thr);
The first constructor constructs a thread object that does not observes any thread.
The second constructor constructs a joinable thread object that observes a new thread executing func(), where func is the name of a function that takes no arguments and returns void, or the name of an object of a class that provides an operator() that takes no arguments and returns void. The constructor does not return until the new thread has begun execution.
The third constructor constructs a thread object in the same state as other and leaves other in a default-constructed state.
The fourth constructor constructs a thread object that manages the thread managed by thrd. After the call, thrd does not manage any thread.
~thread();
If the thread object manages a thread and that thread is joinable, the destructor calls cancel() and then calls detach(). Otherwise, it does nothing.
id() throw();
The constructor constructs an object of type id.
bool operator==(const thread::id& left, const thread& right);
The function returns true only if left and right were both constructed with the default constructor or if left and right refer to the same thread.
bool operator!=(const thread::id& left, const thread& right);
The function returns !(left == right).
class thread_canceled { public: thread_canceled() throw(); virtual ~thread_canceled() throw(); virtual const char *what() const throw(); };
The class describes an exception thrown to indicate that the thread in which it was thrown is being cancelled.
thread_canceled();
The constructor constructs an object of type thread_canceled.
~thread_canceled();
The destructor destroys an object of type thread_canceled.
const char *what() const throw();
The member function returns an implementation-defined NTBS.
The message may be a null-terminated miltibyte string, suitable for conversion and display as a wstring. The return value remains valid until the object from which it is obtained is destroyed or a non-const member function of the object is called.
class thread_group { public: thread_group(); ~thread_group(); template <class Func> thread *create_thread(Func func); void add_thread(thread *thrd); void remove_thread(thread *thrd); void join_all(); // exposition only private: // not implemented thread_group(const thread_group&); thread_group& operator= (const thread_group&); };
The class describes an object for observing the states of multiple objects of class thread (join_all) without having to observe each of the threads individually. Objects of class thread to be observed by a thread_group object must be created with new; they will be destroyed by the thread_group object's destructor. Objects of class thread_group cannot be copied.
void add_thread(thread *thrd);
Requires *thrd must be joinable.
The member function adds *thrd to the group of thread objects observed by the thread_group object. Calling add_thread with a thread object that is already in the group does nothing.
template <class Func>
thread *create_thread(Func func);
The member function calls thread *res = new thread(func), and if the call succeeds calls add_thread(res). It returns res.
void join_all();
The member function effectively calls thr.join() for each thread object thr in the group of thread objects observed by the thread_group object.
void remove_thread(thread *thrd);
The member function removes *thrd from the group of thread objects observed by the thread_group object. If *thrd is not in the group the function does nothing.
thread_group();
The constructor constructs a thread_group object with an empty group of thread objects.
~thread_group();
The destructor effectively executes delete thrd for every thread object *thrd in the group.
class thread_resource_error
: public std::runtime_error
{
public:
thread_resource_error();
};
The class describes an exception thrown to indicate that an attempted operation failed because a required resource other than memory was not available.
template <class T> class thread_specific_ptr { public: thread_specific_ptr(); thread_specific_ptr(tss_t); ~thread_specific_ptr(); T *get() const; T *operator->() const; T& operator*() const; T *release(); void reset(T *ptr = 0); typedef unspecified native_tss_handle; native_tss_handle native_handle() const; tss_t c_handle() const; // exposition only private: T *data; // not implemented thread_specific_ptr::thread_specific_ptr(const thread_specific_ptr&); thread_specific_ptr<T>& thread_specific_ptr::operator= (const thread_specific_ptr<T>&); };
The template class describes an object that controls thread-specific storage for a data object of type T or of a type derived from T. The template holds a pointer data of type T*; the stored value data can be different in different threads, so threads can use different data objects, accessed through the same thread_specific_ptr object. Objects of class thread_specific_ptr<T> cannot be copied.
tss_t c_handle() const;
The member function returns an object of type tss_t that can be passed to functions in the C interface for operations on this thread-specific storage object.
T *get() const;
The member function returns the thread-specific stored value data.
native_tss_handle native_handle() const;
The member function returns an object that can be passed to an implementation-defined set of system functions for operations on the thread-specific storage managed by this object.
typedef unspecified native_tss_handle;
The typedef names a type for objects that can be passed to an implementation-defined set of system functions for operations on the thread-specific storage managed by this object.
T *operator->() const;
Requires get() != 0.
The member function returns the thread-specific stored value data.
T& operator*() const;
Requires get() != 0.
The member function returns *get().
T *release();
The member function sets the thread-specific stored value data to 0 and returns the previous value of the stored value data.
void reset(T *ptr = 0);
The member function does nothing if the thread-specific stored value data equals ptr; otherwise it deletes the thread-specific stored value data and sets the thread-specific stored value data to ptr.
thread_specific_ptr(); thread_specific_ptr(tss_t tss);
The first constructor constructs a thread_specific_ptr<T> object with initial stored value data equal to 0 for all threads. The second constructor constructs a thread_specific_ptr<T> that points to the same thread-specific storage as tss.
~thread_specific_ptr();
The destructor frees resources used by the object. It does not delete thread-specific data pointers.
class timed_mutex { public: timed_mutex(); timed_mutex(mtx_t); ~timed_mutex(); typedef SL0 scoped_lock; typedef SL1 scoped_try_lock; typedef SL2 scoped_timed_lock; typedef unspecified native_timed_mutex_handle; native_thread_handle native_handle() const; mtx_t c_handle() const; // exposition only private: // not implemented timed_mutex(const timed_mutex&); timed_mutex& operator= (const timed_mutex&); };
The class describes an object that can be used with a scoped lock, a scoped try lock or a scoped timed lock to provide a non-recursive mutex that supports test and return and timeout. Objects of class timed_mutex cannot be copied.
mtx_t c_handle() const;
The member function returns an object of type mtx_t that can be passed to functions in the C interface for operations on this mutex.
native_timed_mutex_handle native_handle() const;
The member function returns an object that can be passed to an implementation-defined set of system functions for operations on the mutex managed by this object.
typedef unspecified native_timed_mutex_handle;
The typedef names a type for objects that can be passed to an implementation-defined set of system functions for operations on the mutex managed by this object.
timed_mutex(); timed_mutex(mtx_t mtx);
The first constructor constructs a timed_mutex in the unlocked state. The second constructor constructs a timed_mutex in the same state as mtx.
~timed_mutex();
Requires the object must not be locked.
The destructor releases any resources used by the object.
class try_mutex { public: try_mutex(); try_mutex(mtx_t); ~try_mutex(); typedef SL0 scoped_lock; typedef SL1 scoped_try_lock; typedef unspecified native_try_mutex_handle; native_thread_handle native_handle() const; mtx_t c_handle() const; // exposition only private: // not implemented try_mutex(const try_mutex&); try_mutex& operator= (const try_mutex&); };
The class describes an object that can be used with a scoped lock or a scoped try lock to provide a non-recursive mutex that supports test and return. Objects of class try_mutex cannot be copied.
mtx_t c_handle() const;
The member function returns an object of type mtx_t that can be passed to functions in the C interface for operations on this mutex.
native_try_mutex_handle native_handle() const;
The member function returns an object that can be passed to an implementation-defined set of system functions for operations on the mutex managed by this object.
typedef unspecified native_try_mutex_handle;
The typedef names a type for objects that can be passed to an implementation-defined set of system functions for operations on the mutex managed by this object.
try_mutex(); try_mutex(mtx_t mtx);
The first constructor constructs a try_mutex in the unlocked state. The second constructor constructs a try_mutex in the same state as mtx.
~try_mutex();
Requires the object must not be locked.
The destructor releases any resources used by the object.
void yield();
The function requests the runtime system to put the calling thread at the back of the execution queue for threads with the same priority as the calling thread.
Copyright © 2007 by Roundhouse Consulting, Ltd. Permission is granted to use this document for standardization purposes.
This document is derived in part from A Multi-threading Library for Standard C++, Revision 1, Copyright © 2002-2005 by Dinkumware, Ltd.
That document is, in turn, derived in part from a document bearing the following restrictions:
© Copyright William E. Kempf 2001
Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. William E. Kempf makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty.