您的位置:首页 > 其它

Thread Interruption in Boost Thread Library

2011-11-04 10:04 337 查看
One of the new features introduced in the upcoming 1.35.0 release of the
boost thread library is support for interruption of a running thread. Similar to the Java and .NET interruption support, this allows for one thread to request another thread to stop at the nextinterruption point. This is the only way to
explicitly request a thread to terminate that is directly supported by the Boost Thread library, though users can manually implement cooperative interruption if required.

Interrupting a thread in this way is much less dangerous than brute-force tactics such as
TerminateThread()
, as such tactics can leave broken invariants and leak resources. If a thread is killed using a brute-force method and it was holding any
locks, this can also potentially lead to deadlock when another thread tries to acquire those locks at some future point. Interruption is also easier and more reliable than rolling your own cooperative termination scheme using mutexes, flags, condition variables,
or some other synchronization mechanism, since it is part of the library.

Interrupting a Thread

A running thread can be interrupted by calling the
interrupt()
member function on the corresponding
boost::thread
object. If the thread doesn't have a
boost::thread
object (e.g the initial thread of the application), then it cannot be interrupted.

Calling
interrupt()
just sets a flag in the thread management structure for that thread and returns: it doesn't wait for the thread to actually be interrupted. This is important, because a thread can only be interrupted at one of the predefinedinterruption
points, and it might be that a thread never executes an interruption point, so never sees the request. Currently, 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()


When a thread reaches one of these interruption points, if interruption is enabled for that thread then it checks its interruption flag. If the flag is set, then it is cleared, and a
boost::thread_interrupted
exception is thrown. If the thread
is already blocked on a call to one of the interruption points with interruption enabled when
interrupt()
is called, then the thread will wake in order to throw the
boost::thread_interrupted
exception.

Catching an Interruption

boost::thread_interrupted
is just a normal exception, so it can be caught, just like any other exception. This is why the "interrupted" flag is cleared when the exception is thrown — if a thread catches and handles the interruption, it is perfectly
acceptable to interrupt it again. This can be used, for example, when a worker thread that is processing a series of independent tasks — if the current task is interrupted, the worker can handle the interruption and discard the task, and move onto the next
task, which can then in turn be interrupted. It also allows the thread to catch the exception and terminate itself by other means, such as returning error codes, or translating the exception to pass through module boundaries.

Disabling Interruptions

Sometimes it is necessary to avoid being interrupted for a particular section of code, such as in a destructor where an exception has the potential to cause immediate process termination. This is done by constructing 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
}


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 disabled again
{
boost::this_thread::disable_interruption di2;
// interruption disabled
{
boost::this_thread::restore_interruption ri2(di2);
// interruption still disabled
// as it was disabled when di2 constructed
} // ri2 destroyed, interruption still disabled
} //di2 destroyed, interruption still disabled
} // di destroyed, interruption state restored
// interruption now enabled
}


boost::this_thread::disable_interruption
and
boost::this_thread::restore_interruption
cannot be moved or copied, and they are the only way of enabling and disabling interruption. This ensures that the interruption state is correctly
restored when the scope is exited (whether normally, or by an exception), and that you cannot enable interruptions in the middle of an interruption-disabled block unless you're in full control of the code, and have access to the
boost::this_thread::disable_interruption

instance.

At any point, the interruption state for the current thread can be queried by calling
boost::this_thread::interruption_enabled()
.

Cooperative Interruption

As well as the interruption points on blocking operations such as
sleep()
and
join()
, there is one interruption point explicitly designed to allow interruption at a user-designated point in the code.
boost::this_thread::interruption_point()

does nothing except check for an interruption, and can therefore be used in long-running code that doesn't execute any other interruption points, in order to allow for cooperative interruption. Just like the other interruption points,
interruption_point()
respects the interruption enabled state, and does nothing if interruption is disabled for the current thread.

Interruption is Not Cancellation

On POSIX platforms, threads can be cancelled rather than killed, by calling
pthread_cancel()
. This is similar to interruption, but is a separate mechanism, with different behaviour. In particular, cancellation cannot be stopped once it is started: whereas interruption just throws an exception, once a cancellation request has
been acknowledged the thread is effectively dead.
pthread_cancel()
does not always execute destructors either (though it does on some platforms), as it is primarily a C interface — if you want to clean up your resources when a thread is cancelled,
you need to use
pthread_cleanup_push()
to register a cleanup handler. The advantage here is that
pthread_cleanup_push()
works in C stack frames, whereas exceptions don't play nicely in C: on some platforms it will crash your program
for an exception to propagate into a C stack frame.

For portable code, I recommend interruption over cancellation. It's supported on all platforms that can use the Boost Thread library, and it works well with C++ code — it's just another exception, so all your destructors and catch blocks work just fine.

Posted by Anthony Williams

From:http://www.justsoftwaresolutions.co.uk/threading/thread-interruption-in-boost-thread-library.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐