9.2.6. Обработка прерываний
С точки зрения прерываемого потока, прерывание — это просто исключение типа thread_interrupted, которое, следовательно, можно обработать, как любое другое исключение. В частности, его можно перехватить в стандартном блоке catch:
try {
do_something();
} catch (thread_interrupted&) {
handle_interruption();
}
Таким образом, прерывание можно перехватить, каким-то образом обработать и потом спокойно продолжить работу. Если мы так поступим, а потом другой поток еще раз вызовет interrupt(), то поток будет снова прерван, когда в очередной раз вызовет функцию interruption_point(). Возможно, это и неплохо, если вы выполняете последовательность независимых задач; текущая задача будет прервана, а поток благополучно перейдёт к следующей задаче в списке.
Поскольку thread_interrupted — исключение, то при вызове кода, который может быть прерван, следует принимать все обычные для исключений меры предосторожности, чтобы не было утечки ресурсов, и структуры данных оставались согласованными. Часто желательно завершать поток в случае прерывания, так чтобы исключение можно было просто передать вызывающей функции. Но если позволить исключению выйти за пределы функции потока, переданной конструктору std::thread, то будет вызвана функция std::terminate(), что приведёт к завершению всей программы. Чтобы не помещать обработчик catch(thread_interrupted) в каждую функцию, которая передаётся interruptible_thread, можно включить блок catch в обертку, служащую для инициализации interrupt_flag. Тогда распространять необработанное исключение будет безопасно, так как завершится лишь отдельный поток. Инициализация потока в конструкторе interruptible_thread при таком подходе выглядит следующим образом:
internal_thread = std::thread([f, &p] {
p.set_value(&this_thread_interrupt_flag);
try {
f();
} catch(thread_interrupted const&) {}
});
А теперь рассмотрим конкретный пример, когда прерывание оказывается полезно.