| Document Number: | WG14 N1269 |
| Date: | 2007-11-10 |
| Reply to: | P.J. Plauger |
| Document number: | WG21 N1907=05-0167 |
| Date: | 2005-10-19 |
| Project: | Programming Language C++ |
| Reference: | ISO/IEC IS 14882:2003(E) |
| Reply to: | Pete Becker |
| Dinkumware, Ltd. | |
| petebecker@acm.org |
Overview · Memory Visibility · Condition Variables · Mutexes · Once Functions · Thread-specific Storage · Open Issues
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.
The Dinkum Threads 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. Thus, 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.
native_thrd_t whose content
is unspecified, and two global functions,
native_thrd_t get_thrd_t(const thread&) for C++ thread objects and
native_thrd_t get_thrd_t(thrd_t) for C thread identifiers.HANDLE
and a thread identifier, in different contexts.xtime stuff with the new Date/Time stuff.class barrier to synchronize multiple threads and
variations on class read_write_mutex for synchronizing multiple readers
and writers.operator void* to test
their state. Since we seem to be moving to operator
unspecified-boolean-type for this sort of test, we should probably change
these operators accordingly.call_once
· condition
· lock_error
· mutex
· once_flag
· ONCE_FLAG_INIT
· once_init
· recursive_mutex
· recursive_timed_mutex
· recursive_try_mutex
· thread
· thread_group
· thread_resource_error
· thread_specific_ptr
· timed_mutex
· try_mutex
namespace std {
namespace tr2 {
/* ERROR REPORTING */
class lock_error;
class thread_resource_error;
/* THREADS */
class thread;
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;
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));
} }
call_oncevoid 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.
conditioncondition
· ~condition
· notify_all
· notify_one
· timed_wait
· wait
class condition
{
public:
condition();
~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();
// 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.
condition::conditioncondition();
The constructor constructs a condition object;
a thread that calls wait on a newly
constructed condition object will block.
condition::~condition~condition();
Requires: no threads are blocked waiting for the condition object.
The destructor releases any resources used by the condition object.
condition::notify_onevoid 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.
condition::notify_allvoid 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.
condition::timed_waittemplate <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.
condition::waittemplate <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.
lock_errorclass 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.
once_flagtypedef o-type once_flag;
The type describes a data object for use as the first argument to
call_once.
ONCE_FLAG_INIT#define ONCE_FLAG_INIT <object initializer>
The macro yields a value that can be used to initialize an object of type once_flag.
once_initconst once_flag once_init = .....;
The object provides an initial value for objects of type once_flag.
mutexmutex
· ~mutex
· scoped_lock
class mutex
{
public:
mutex();
~mutex();
typedef SL0 scoped_lock;
// 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.
mutex::mutexmutex();
The constructor constructs a mutex in the unlocked state.
mutex::~mutex~mutex();
Requires: the object must not be locked.
The destructor releases any resources used by the object.
recursive_mutexrecursive_mutex
· ~recursive_mutex
· scoped_lock
class recursive_mutex
{
public:
recursive_mutex();
~recursive_mutex();
typedef SL0 scoped_lock;
// 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.
recursive_mutex::recursive_mutexrecursive_mutex();
The constructor constructs a mutex in the unlocked state.
recursive_mutex::~recursive_mutex~recursive_mutex();
Requires: the object must not be locked.
The destructor releases any resources used by the object.
recursive_timed_mutexrecursive_timed_mutex
· ~recursive_timed_mutex
· scoped_lock
· scoped_timed_lock
· scoped_try_lock
class recursive_timed_mutex
{
public:
recursive_timed_mutex();
~recursive_timed_mutex();
typedef SL0 scoped_lock;
typedef SL1 scoped_try_lock;
typedef SL2 scoped_timed_lock;
// 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.
recursive_timed_mutex::recursive_timed_mutexrecursive_timed_mutex();
The constructor constructs a recursive_timed_mutex in the unlocked state.
recursive_timed_mutex::~recursive_timed_mutex~recursive_timed_mutex();
Requires: the object must not be locked.
The destructor releases any resources used by the object.
recursive_try_mutexrecursive_try_mutex
· ~recursive_try_mutex
· scoped_lock
· scoped_try_lock
class recursive_try_mutex
{
public:
recursive_try_mutex();
~recursive_try_mutex();
typedef SL0 scoped_lock;
typedef SL1 scoped_try_lock;
// 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.
recursive_try_mutex::recursive_try_mutexrecursive_try_mutex();
The constructor constructs a recursive_try_mutex in the unlocked state.
recursive_try_mutex::~recursive_try_mutex~recursive_try_mutex();
Requires: the object must not be locked.
The destructor releases any resources used by the object.
scoped_locklock
· locked
· mutex_type
· operator const void *
· scoped_lock
· ~scoped_lock
· unlock
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&);
};
scoped_lock::lockvoid lock();
The member function locks the stored mutual exclusion object mm
and sets the stored value is_locked to true.
scoped_lock::lockedbool locked() const;
The member function returns the stored value is_locked.
scoped_lock::mutex_typetypedef mtx mutex_type;
The nested type is a synonym for the containing type mtx.
scoped_lock::operator const void *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::scoped_lockscoped_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::~scoped_lock~scoped_lock();
The destructor calls unlock if the stored value is_locked
is true. Otherwise the destructor does nothing.
scoped_lock::unlockvoid 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.
scoped_timed_locklock
· locked
· mutex_type
· operator const void *
· scoped_timed_lock
· ~scoped_timed_lock
· timed_lock
· unlock
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&);
};
scoped_timed_lock::lockvoid lock();
The member function locks the stored mutual exclusion object mm
and sets the stored value is_locked to true.
scoped_timed_lock::lockedbool locked() const;
The member function returns the stored value is_locked.
scoped_timed_lock::mutex_typetypedef mtx mutex_type;
The nested type is a synonym for the containing type mtx.
scoped_timed_lock::operator const void *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::scoped_timed_lockscoped_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::~scoped_timed_lock~scoped_timed_lock();
The destructor calls unlock if the stored value is_locked
is true. Otherwise the destructor does nothing.
scoped_timed_lock::timed_lockbool 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.
scoped_timed_lock::unlockvoid 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.
scoped_try_locklock
· locked
· mutex_type
· operator const void *
· scoped_try_lock
· ~scoped_try_lock
· try_lock
· unlock
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&);
};
scoped_try_lock::lockvoid lock();
The member function locks the stored mutual exclusion object mm
and sets the stored value is_locked to true.
scoped_try_lock::lockedbool locked() const;
The member function returns the stored value is_locked.
scoped_try_lock::mutex_typetypedef mtx mutex_type;
The nested type is a synonym for the containing type mtx.
scoped_try_lock::operator const void *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::scoped_try_lockscoped_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::~scoped_try_lock~scoped_try_lock();
The destructor calls unlock if the stored value is_locked
is true. Otherwise the destructor does nothing.
scoped_try_lock::try_lockbool 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.
scoped_try_lock::unlockvoid 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.
threadjoin
· operator!=
· operator==
· sleep
· thread
· yield
class thread
{
public:
thread();
template <class Func>
explicit thread(Func func);
bool operator== (const thread& other) const;
bool operator!= (const thread& other) const
{return !operator==(other); }
void join();
static void sleep(const xtime& xt);
static void yield();
// exposition only
private:
// not implemented
thread(const thread&);
thread& operator= (const thread&);
};
The class describes an object for observing the state of a thread
(join) and managing the state of the current
thread (sleep,
yield).
Objects of class thread cannot be copied.
A thread object is joinable if
it was constructed as a joinable object, the application has not made a
call to thread::join for that object, and the
application has not made a call to
thread_group::join_all for a
thread_group object observing that thread object.
thread::joinvoid join();
Requires: the object must be joinable.
The member function marks this thread object
as non-joinable then blocks until the thread observed by this
thread object terminates.
thread::operator!=bool operator!= (const thread& other) const
{return !operator==(other); }
Requires: the observed thread has not terminated.
The member function returns !operator==(other).
thread::operator==bool operator== (const thread& other) const;
Requires: the observed thread has not terminated.
The member function returns true only if this thread
object and other observe the same thread.
thread::sleepstatic void sleep(const xtime& xt);
The static member function blocks the calling thread
at least until the time specified by the joinable
thread object that observes the thread
that constructed the object.
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.
thread::threadthread();
template<class Func>
explicit thread(Func func);
The first constructor constructs a non-joinable
thread object that observes the thread
that constructed the object.
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.
thread::yieldstatic void yield();
The member 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.
thread_groupadd_thread
· create_thread
· join_all
· remove_thread
· thread_group
· ~thread_group
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.
thread_group::add_threadvoid 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.
thread_group::create_threadtemplate <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.
thread_group::join_allvoid 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.
thread_group::remove_threadvoid 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::thread_groupthread_group();
The constructor constructs a thread_group object with an empty
group of thread objects.
thread_group::~thread_group~thread_group();
The destructor effectively executes delete thrd for every thread
object *thrd in the group.
thread_resource_errorclass 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.
thread_specific_ptrget
· operator->
· operator*
· release
· reset
· thread_specific_ptr
· ~thread_specific_ptr
template <class T>
class thread_specific_ptr
{
public:
thread_specific_ptr();
~thread_specific_ptr();
T *get() const;
T *operator->() const;
T& operator*() const;
T *release();
void reset(T *ptr = 0);
// 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.
thread_specific_ptr::getT *get() const;
The member function returns the thread-specific stored value data.
thread_specific_ptr::operator->T *operator->() const;
Requires:
get() != 0.
The member function returns the thread-specific stored value data.
thread_specific_ptr::operator*T& operator*() const;
Requires:
get() != 0.
The member function returns *get().
thread_specific_ptr::releaseT *release();
The member function sets the thread-specific stored value data to 0
and returns the previous value of the stored value data.
thread_specific_ptr::resetvoid 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_ptrthread_specific_ptr();
The constructor constructs a thread_specific_ptr<T> object
with initial stored value data equal to 0 for all threads.
thread_specific_ptr::~thread_specific_ptr~thread_specific_ptr();
The destructor frees resources used by the object. It does not delete thread-specific data pointers.
timed_mutexscoped_lock
· scoped_timed_lock
· scoped_try_lock
· timed_mutex
· ~timed_mutex
class timed_mutex
{
public:
timed_mutex();
~timed_mutex();
typedef SL0 scoped_lock;
typedef SL1 scoped_try_lock;
typedef SL2 scoped_timed_lock;
// 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.
timed_mutex::timed_mutextimed_mutex();
The constructor constructs a timed_mutex in the unlocked state.
timed_mutex::~timed_mutex~timed_mutex();
Requires: the object must not be locked.
The destructor releases any resources used by the object.
try_mutexscoped_lock
· scoped_try_lock
· try_mutex
· ~try_mutex
class try_mutex
{
public:
try_mutex();
~try_mutex();
typedef SL0 scoped_lock;
typedef SL1 scoped_try_lock;
// 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.
try_mutex::try_mutextry_mutex();
The constructor constructs a try_mutex in the unlocked state.
try_mutex::~try_mutex~try_mutex();
Requires: the object must not be locked.
The destructor releases any resources used by the object.
call_once
· cnd_broadcast
· cnd_destroy
· cnd_init
· cnd_signal
· cnd_t
· cnd_timedwait
· cnd_wait
· mtx_destroy
· mtx_init
· mtx_lock
· mtx_plain
· mtx_recursive
· mtx_t
· mtx_timed
· mtx_timedlock
· mtx_try
· mtx_trylock
· mtx_unlock
· once_flag
· ONCE_FLAG_INIT
· thrd_busy
· thrd_create
· thrd_current
· thrd_detach
· thrd_equal
· thrd_error
· thrd_exit
· thrd_join
· thrd_nomem
· thrd_sleep
· thrd_start_t
· thrd_success
· thrd_t
· thrd_timedout
· thrd_yield
· TIME_UTC
· tss_create
· TSS_DTOR_ITERATIONS
· tss_delete
· tss_dtor_t
· tss_get
· tss_set
· tss_t
· xtime
· xtime_get
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);
cnd_broadcastint cnd_broadcast(cnd_t *cond);
Returns: 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.
cnd_destroyvoid cnd_destroy(cnd_t *cond);
Requires:
no threads are blocked waiting for *cond.
The function releases any resources used by the
condition variable *cond.
cnd_initint 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.
cnd_signalint 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.
cnd_ttypedef o-type cnd_t;
The type is an object type o-type that holds an identifier for a condition variable.
cnd_timedwaitint 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.
cnd_waitint 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.
mtx_destroyvoid mtx_destroy(mtx_t *mtx);
Requires:
no threads are blocked waiting for *mtx.
The function releases any resources used by the
mutex *mtx.
mtx_initint 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
mtx_plain -- for a simple
non-recursive mutexmtx_timed -- for a
non-recursive mutex that supports timeoutmtx_try -- for a
non-recursive mutex that supports test and returnmtx_plain | mtx_recursive -- for a simple
recursive mutexmtx_timed | mtx_recursive -- for a
recursive mutex that supports timeoutmtx_try | mtx_recursive -- for a
recursive mutex that supports test and returnIf it succeeds it sets *mtx to a value that uniquely
identifies the newly created mutex.
mtx_lockint 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.
mtx_plainenum { mtx_plain = ..... };
The compile-time constant is passed to mtx_init to create a mutex object that supports neither timeout nor test and return.
mtx_recursiveenum { mtx_recursive = ..... };
The compile-time constant is passed to mtx_init to create a mutex object that supports recursive locking.
mtx_ttypedef o-type mtx_t;
The type is an object type o-type that holds an identifier for a mutex.
mtx_timedenum { mtx_timed = ..... };
The compile-time constant is passed to mtx_init to create a mutex object that supports timeout.
mtx_timedlockint 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.
mtx_tryenum { mtx_try = ..... };
The compile-time constant is passed to mtx_init to create a mutex object that supports test and return.
mtx_trylockint 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.
mtx_unlockint 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.
thrd_busyenum { 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.
thrd_createint 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_currentthrd_t thrd_current(void);
The function returns a value that uniquely identifies the thread that called it.
thrd_detachint 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.
thrd_equalint 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.
thrd_errorenum { thrd_error = ..... };
The compile-time constant is returned by a function to indicate that the requested operation failed.
thrd_exitvoid thrd_exit(int res);
The function terminates execution of the calling
thread and sets its
result code to res.
thrd_joinint 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.
thrd_nomemenum { 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.
thrd_sleepvoid thrd_sleep(const xtime *xt);
The function suspends execution of the calling
thread
until after the time specified by the
xtime object *xt.
thrd_start_ttypedef int (*thrd_start_t)(void*);
The type is the function type that is passed to thrd_create to create a new thread.
thrd_successenum { thrd_success = ..... };
The compile-time constant is returned by a function to indicate that the requested operation succeeded.
thrd_ttypedef o-type thrd_t;
The type is an object type o-type that holds an identifier for a thread.
thrd_timedoutenum { 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.
thrd_yieldvoid thrd_yield(void);
The function permits other threads to run even if the current thread would ordinarily continue to run.
TIME_UTCenum { 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.
tss_createint 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.
TSS_DTOR_ITERATIONS#define TSS_DTOR_ITERATIONS <integer constant expression>
The macro yields the maximum number of times that destructors will be called when a thread terminates.
tss_dtor_ttypedef void (*tss_dtor_t)(void*);
The type is the function type for a destructor for a thread-specific storage pointer.
tss_deletevoid tss_delete(tss_t key);
The function releases any resources used by the
thread-specific storage
pointer key.
tss_getvoid *tss_get(tss_t key);
The function returns the value for the current thread held in the
thread-specific storage
pointer identified by key.
tss_setint 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.
tss_ttypedef o-type tss_t;
The type is an object type o-type that holds an identifier for a thread-specific storage pointer.
xtimetypedef 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.
xtime_getint 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.
Copyright © 2002, 2005 by Dinkumware, Ltd. Permission is granted to use this document for standardization purposes. This material is derived in part from documentation bearing the following restrictions:
© Copyright William E. Kempf 2001Permission 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.