Thread Interruption in Boost Thread Library

来源:互联网 发布:将json对象遍历成数组 编辑:程序博客网 时间:2024/05/29 06:50

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 asTerminateThread(), 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 correspondingboost::thread object. If the thread doesn't have aboost::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:

[cpp] view plaincopy
  1.        boost::thread::join()  
  2. boost::thread::timed_join()  
  3. boost::condition_variable::wait()  
  4. boost::condition_variable::timed_wait()  
  5. boost::condition_variable_any::wait()  
  6. boost::condition_variable_any::timed_wait()  
  7. boost::this_thread::sleep()  
  8. 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 aboost::thread_interrupted exception is thrown. If the thread is already blocked on a call to one of the interruption points with interruption enabled wheninterrupt() is called, then the thread will wake in order to throw theboost::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 ofboost::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:

[cpp] view plaincopy
  1. void f()  
  2. {  
  3.     // interruption enabled here  
  4.     {  
  5.         boost::this_thread::disable_interruption di;  
  6.         // interruption disabled  
  7.         {  
  8.             boost::this_thread::disable_interruption di2;  
  9.             // interruption still disabled  
  10.         } // di2 destroyed, interruption state restored  
  11.         // interruption still disabled  
  12.     } // di destroyed, interruption state restored  
  13.     // interruption now enabled  
  14. }  



effects of an instance of boost::this_thread::disable_interruption can be temporarily reversed by constructing an instance ofboost::this_thread::restore_interruption, passing in theboost::this_thread::disable_interruption object in question. This will restore the interruption state to what it was when theboost::this_thread::disable_interruption object was constructed, and then disable interruption again when theboost::this_thread::restore_interruption object is destroyed:

[cpp] view plaincopy
  1. void g()  
  2. {  
  3.     // interruption enabled here  
  4.     {  
  5.         boost::this_thread::disable_interruption di;  
  6.         // interruption disabled  
  7.         {  
  8.             boost::this_thread::restore_interruption ri(di);  
  9.             // interruption now enabled  
  10.         } // ri destroyed, interruption disabled again  
  11.         {  
  12.             boost::this_thread::disable_interruption di2;  
  13.             // interruption disabled  
  14.             {  
  15.                 boost::this_thread::restore_interruption ri2(di2);  
  16.                 // interruption still disabled  
  17.                 // as it was disabled when di2 constructed  
  18.             } // ri2 destroyed, interruption still disabled  
  19.         } //di2 destroyed, interruption still disabled  
  20.     } // di destroyed, interruption state restored  
  21.     // interruption now enabled  
  22. }  


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 theboost::this_thread::disable_interruption instance.

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

Cooperative Interruption

As well as the interruption points on blocking operations such as sleep() andjoin(), 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 thatpthread_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

0 0
原创粉丝点击