Если состояние отмены потока, как это описывалось ранее, установлено в
PTHREAD_CANCEL_DISABLE
, то никакая расстановка точек отмены не имеет эффекта и поток остается неотменяемым.
Покажем, как могут быть использованы все эти предосторожности в коде функции потока, чтобы сделать код безопасным с позиции возможной асинхронной отмены потока извне:
Наконец, в QNX (но не в POSIX) существует вызов, подобный
pthread_cancel
, принудительно отменяющий поток независимо от его установок («желания»):
int pthread_abort(pthread_t thread);
В отличие от
pthread_cancel
, этот вызов принудительно и немедленно отменяет поток. Кроме того, никакие процедуры завершения и деструкторы собственных данных потока не выполняются. Очевидно, что в результате такого «завершения» состояния объектов процесса будут просто неопределенными, поэтому такой вызов крайне опасен. При таком способе отмены в программный код, ожидающий завершения на
pthread_join
, в качестве результата завершения возвращается константа (тип
void*
)
PTHREAD_ABORTED
(аналогично возвращается константа
PTHREAD_CANCELED
при выполнении
pthread_cancel
).
Но и этих мер безопасности недостаточно на все случаи жизни, поэтому механизм потоков предусматривает еще один уровень (механизм) страховки.
Стек процедур завершения
Для поддержания корректности состояния объектов процесса каждый поток может помещать (добавлять) в стек процедур завершения (thread's cancellation-cleanup stack) функции, которые при завершении (
pthread_exit
или
return
) или отмене (по
pthread_cancel
) выполняются в порядке, обратном помещению. Для манипуляции со стеком процедур завершения предоставляются вызовы (оба вызова реализуются макроопределениями, но это не суть важно [24] ):
24
Разница выражается в том, что макрос
pthread_cleanup_push
расширяется
в фрагмент кода, открывающийся скобкой «{» без соответствующей скобки «}», аналогично
pthread_cleanup_pop
закрывается «}», не имея открывающей скобки. Эти вызовы могут располагаться только парами, в противном случае возникнет лексическая ошибка, обнаруживаемая компилятором.
// все точки отмены должны быть расставлены в этом блоке!
}
pthread_testcancel;
pthread_cleanup_pop(1);
}
}
«Легковесность» потока
Вот теперь, завершив краткий экскурс использования процессов и потоков, можно вернуться к вопросу, который вскользь уже звучал по ходу рассмотрения: почему и в каком смысле потоки часто называют «легкими процессами» (LWP — lightweight process)?
Выполним ряд тестов по сравнительной оценке временных затрат на создание процесса и потока. Начнем с процесса ( файл p2-1.cc):