![]() |
Home | Libraries | People | FAQ | More |
The boost::thread
class is responsible for launching and managing threads. Each boost::thread
object represents a single
thread of execution, or Not-a-Thread, and at most one
boost::thread
object represents a given thread of execution: objects of type boost::thread
are not copyable.
Objects of type boost::thread
are movable, however, so
they can be stored in move-aware containers, and returned from functions.
This allows the details of thread creation to be wrapped in a function.
boost::thread make_thread(); void f() { boost::thread some_thread=make_thread(); some_thread.join(); }
![]() |
Note |
---|---|
On compilers that support rvalue references, For other compilers, move support is provided with a move emulation layer, so containers must explicitly detect that move emulation layer. See <boost/thread/detail/move.hpp> for details. |
A new thread is launched by passing an object of a callable type that can
be invoked with no parameters to the constructor. The object is then copied
into internal storage, and invoked on the newly-created thread of execution.
If the object must not (or cannot) be copied, then boost::ref
can be used to pass in a reference to the function object. In this case,
the user of Boost.Thread must ensure that
the referred-to object outlives the newly-created thread of execution.
struct callable { void operator()(); }; boost::thread copies_are_safe() { callable x; return boost::thread(x); } // x is destroyed, but the newly-created thread has a copy, so this is OK boost::thread oops() { callable x; return boost::thread(boost::ref(x)); } // x is destroyed, but the newly-created thread still has a reference // this leads to undefined behaviour
If you wish to construct an instance of boost::thread
with a function or callable
object that requires arguments to be supplied, this can be done by passing
additional arguments to the boost::thread
constructor:
void find_the_question(int the_answer); boost::thread deep_thought_2(find_the_question,42);
The arguments are copied into the internal thread
structure: if a reference is required, use boost::ref
,
just as for references to callable functions.
There is an unspecified limit on the number of additional arguments that can be passed.
Thread launched in this way are created with implementation defined thread attributes as stack size, scheduling, priority, ... or any platform specific attributes. It is not evident how to provide a portable interface that allows the user to set the platform specific attributes. Boost.Thread stay in the middle road through the class thread::attributes which allows to set at least in a portable way the stack size as follows:
boost::thread::attributes attrs; attrs.set_stack_size(4096*10); boost::thread deep_thought_2(attrs, find_the_question, 42);
Even for this simple attribute there could be portable issues as some platforms could require that the stack size should have a minimal size and/or be a multiple of a given page size. The library adapts the requested size to the platform constraints so that the user doesn't need to take care of it.
This is the single attribute that is provided in a portable way. In order to set any other thread attribute at construction time the user needs to use non portable code.
On PThread platforms the user will need to get the thread attributes handle and use it for whatever attribute.
Next follows how the user could set the stack size and the scheduling policy on PThread platforms.
boost::thread::attributes attrs; // set portable attributes // ... attr.set_stack_size(4096*10); #if defined(BOOST_THREAD_PLATFORM_WIN32) // ... window version #elif defined(BOOST_THREAD_PLATFORM_PTHREAD) // ... pthread version pthread_attr_setschedpolicy(attr.native_handle(), SCHED_RR); #else #error "Boost threads unavailable on this platform" #endif boost::thread th(attrs, find_the_question, 42);
On Windows platforms it is not so simple as there is no type that compiles the thread attributes. There is a linked to the creation of a thread on Windows that is emulated via the thread::attributes class. This is the LPSECURITY_ATTRIBUTES lpThreadAttributes. Boost.Thread provides a non portable set_security function so that the user can provide it before the thread creation as follows
#if defined(BOOST_THREAD_PLATFORM_WIN32) boost::thread::attributes attrs; // set portable attributes attr.set_stack_size(4096*10); // set non portable attribute LPSECURITY_ATTRIBUTES sec; // init sec attr.set_security(sec); boost::thread th(attrs, find_the_question, 42); // Set other thread attributes using the native_handle_type. //... #else #error "Platform not supported" #endif
If the function or callable object passed to the boost::thread
constructor propagates
an exception when invoked that is not of type boost::thread_interrupted
,
std::terminate()
is called.
A thread can be detached by explicitly invoking the detach()
member function on the boost::thread
object. In this case, the
boost::thread
object ceases to represent the now-detached thread, and instead represents
Not-a-Thread.
int main() { boost::thread t(my_func); t.detach(); }
In order to wait for a thread of execution to finish, the join()
,
__join_for or __join_until ( timed_join()
deprecated) member functions of the boost::thread
object must be used. join()
will block the calling thread
until the thread represented by the boost::thread
object has completed.
int main() { boost::thread t(my_func); t.join(); }
If the thread of execution represented by the boost::thread
object has already completed,
or the boost::thread
object represents Not-a-Thread, then join()
returns immediately.
int main() { boost::thread t; t.join(); // do nothing }
Timed based join are similar, except that a call to __join_for or __join_until will also return if the thread being waited for does not complete when the specified time has elapsed or reached respectively.
int main() { boost::thread t; if ( t.join_for(boost::chrono::milliseconds(500)) ) // do something else t.join(); // join anyway }
When the boost::thread
object that represents
a thread of execution is destroyed the thread becomes detached.
Once a thread is detached, it will continue executing until the invocation
of the function or callable object supplied on construction has completed,
or the program is terminated. A thread can also be detached by explicitly
invoking the detach()
member function on the boost::thread
object. In this case, the
boost::thread
object ceases to represent the now-detached thread, and instead represents
Not-a-Thread.
When the boost::thread
object that represents
a thread of execution is destroyed the program terminates if the thread
is __joinable__.
int main() { boost::thread t(my_func); } // calls std::terminate()
You can use a thread_joiner to ensure that the thread has been joined at the thread destructor.
int main() { boost::thread t(my_func); boost::thread_joiner g(t); // do something else } // here the thread_joiner destructor will join the thread before it is destroyed.
A running thread can be interrupted by invoking the
interrupt()
member function of the corresponding boost::thread
object. When the interrupted
thread next executes one of the specified interruption
points (or if it is currently blocked
whilst executing one) with interruption enabled, then a boost::thread_interrupted
exception will be thrown in the interrupted thread. If not caught, this
will cause the execution of the interrupted thread to terminate. As with
any other exception, the stack will be unwound, and destructors for objects
of automatic storage duration will be executed.
If a thread wishes to avoid being interrupted, it can create an instance
of boost::this_thread::disable_interruption
. Objects
of this class disable interruption for the thread that created them on
construction, and restore the interruption state to whatever it was before
on destruction:
void f() { // interruption enabled here { boost::this_thread::disable_interruption di; // interruption disabled { boost::this_thread::disable_interruption di2; // interruption still disabled } // di2 destroyed, interruption state restored // interruption still disabled } // di destroyed, interruption state restored // interruption now enabled }
The effects of an instance of boost::this_thread::disable_interruption
can be temporarily
reversed by constructing an instance of boost::this_thread::restore_interruption
, passing
in the boost::this_thread::disable_interruption
object in
question. This will restore the interruption state to what it was when
the boost::this_thread::disable_interruption
object was
constructed, and then disable interruption again when the boost::this_thread::restore_interruption
object is
destroyed.
void g() { // interruption enabled here { boost::this_thread::disable_interruption di; // interruption disabled { boost::this_thread::restore_interruption ri(di); // interruption now enabled } // ri destroyed, interruption disable again } // di destroyed, interruption state restored // interruption now enabled }
At any point, the interruption state for the current thread can be queried
by calling boost::this_thread::interruption_enabled()
.
The following functions are interruption points, which
will throw boost::thread_interrupted
if interruption is
enabled for the current thread, and interruption is requested for the current
thread:
boost::thread::join()
boost::thread::timed_join()
boost::thread
::try_join_for
()
,
boost::thread
::try_join_until
()
,
boost::condition_variable::wait()
boost::condition_variable::timed_wait()
boost::condition_variable
::wait_for
()
boost::condition_variable
::wait_until
()
boost::condition_variable_any::wait()
boost::condition_variable_any::timed_wait()
boost::condition_variable_any
::wait_for
()
boost::condition_variable_any
::wait_until
()
boost::thread::sleep()
boost::this_thread::sleep_for
()
boost::this_thread::sleep_until
()
boost::this_thread::interruption_point()
Objects of class boost::thread::id
can be used to identify threads.
Each running thread of execution has a unique ID obtainable from the corresponding
boost::thread
by calling the get_id()
member function, or by calling boost::this_thread::get_id()
from within the thread. Objects of class
boost::thread::id
can be copied, and used as keys in associative containers: the full range
of comparison operators is provided. Thread IDs can also be written to
an output stream using the stream insertion operator, though the output
format is unspecified.
Each instance of boost::thread::id
either refers to some thread,
or Not-a-Thread. Instances that refer to Not-a-Thread
compare equal to each other, but not equal to any instances that refer
to an actual thread of execution. The comparison operators on boost::thread::id
yield a total order for every
non-equal thread ID.
boost::thread
class has members native_handle_type
and native_handle
providing
access to the underlying native handle.
This native handle can be used to change for example the scheduling.
In general, it is not safe to use this handle with operations that can
conflict with the ones provided by Boost.Thread. An example of bad usage
could be detaching a thread directly as it will not change the internals
of the boost::thread
instance, so for example the joinable function will continue to return
true, while the native thread is no more joinable.
thread t(fct); thread::native_handle_type hnd=t.native_handle(); pthread_detach(hnd); assert(t.joinable());
Any thread of execution created using the native interface is called a native thread in this documentation.
The first example of a native thread of execution is the main thread.
The user can access to some synchronization functions related to the native
current thread using the boost::this_thread
yield
, sleep
,
sleep_for
, sleep_until
, functions.
int main() { // ... boost::this_thread::sleep_for(boost::chrono::milliseconds(10)); // ... }
Of course all the synchronization facilities provided by Boost.Thread are also available on native threads.
The boost::this_thread
interrupt related functions
behave in a degraded mode when called from a thread created using the native
interface, i.e. boost::this_thread::interruption_enabled()
returns false. As consequence the use of boost::this_thread::disable_interruption
and boost::this_thread::restore_interruption
will do nothing
and calls to boost::this_thread::interruption_point()
will be just ignored.
As the single way to interrupt a thread is through a boost::thread
instance, interruption_request()
will return false for the native threads.
pthread_exit
POSIX limitation
pthread_exit
in glibc/NPTL
causes a "forced unwind" that is almost like a C++ exception,
but not quite. On Mac OS X, for example, pthread_exit
unwinds without calling C++ destructors.
This behavior is incompatible with the current Boost.Thread design, so the use of this function in a POSIX thread result in undefined behavior of any Boost.Thread function.