Identifying Threads
Because threads can now be transferred between objects, the boost::thread
object itself no longer suffices for identification. Consequently there is now a new boost::thread::id
class that holds a thread ID. You can obtain the thread ID from a boost::thread
object by calling the get_id()
member function, or for the current thread by calling boost::this_thread::get_id()
.
This highlights another important difference: You can no longer get a boost::thread
object that represents the "current thread." In old versions of Boost, a default-constructed boost::thread
object was special, in that it represented the current thread. Now, a default-constructed boost::thread
object doesn't represent any thread at all. The only use for such an object was for identifying a thread, and comparison with other boost::thread
objects: This role is now taken by the boost::thread::id
class.
Thread IDs sport the full range of comparison operators, and can be freely copied. If two thread IDs represent the same thread they compare equal, and if they represent different threads then they are not equal. Also, the thread IDs for distinct threads form a total order, so they can be used as keys in associative containers such as std::map<>.
boost::mutex map_mutex; std::map<boost::thread::id, some_data> data_map; void f() { boost::mutex::scoped_lock lk(map_mutex); some_data& my_data=data_map[boost::this_thread::get_id()]; lk.unlock(); do_stuff(my_data); }
A default-constructed boost::thread::id
represents "not any thread," and will not compare equal to any boost::thread::id
that holds the ID of a thread of execution.
Interrupting Threads
The final new aspect of thread management introduced with Boost 1.35.0 is the ability to interrupt a running thread. This is done by calling the interrupt()
member function of the boost::thread
object associated with the thread you wish to interrupt. Interruption is an asynchronous request, and is nonbindingit merely sets a flag in the data structure associated with the thread being interrupted. When that thread reaches an interruption point, it then throws a boost::thread_interrupted
exception if interruption is enabled, and clears the flag. If interruption is disabled, the exception is not thrown and the flag remains set. This is an ordinary C++ exception, and can be caught and handled just like any other exception. In this case, it is perfectly acceptable for the thread to be interrupted again. This can be useful if the thread is performing a series of tasks: If a task is interrupted, the thread can catch the interruption exception and move on to the next task.
The interruption points are:
boost::thread::join()
boost::thread::timed_join()
boost::condition_variable::wait()
boost::condition_variable::timed_wait()
boost::condition_variable_any::wait()
boost::condition_variable_any::timed_wait()
boost::this_thread::sleep()
boost::this_thread::interruption_point()
The last one (boost::this_thread::interruption_point()
) lets you place interruption points at carefully chosen places in your code, when the code would not otherwise execute an interruption point. It can be used as part of a processing loop; for example, if you are processing thousands of items, it might make sense to put an interruption point after every 10 or 100 items to enable relatively timely response to the interruption request.
Interruption is initially enabled for all threads, but can be disabled by constructing an instance of boost::this_thread::disable_interruption
. Interruption is disabled for the lifetime of the disable_interruption
object, but only for the thread that created the object. Typically, such an object would be created as a local variable in order to disable interruption around a specific piece of code. For more about thread interruption see my blog entry, entitled "Thread Interruption in the Boost Thread Library" (www.justsoftwaresolutions.co.uk/threading/ thread-interruption-in-boost-thread-library.html).