Далее, даже если для потока установлено
состояниезавершаемости (также называемое «состоянием отмены»)
PTHREAD_CANCEL_ENABLE
(это значение по умолчанию при создании потока), поток может переопределить еще и
типотмены, вызвав:
int pthread_setcanceltype(int type, int* oldtype);
где
type
и
oldtype
— как и в предыдущем случае, новое и ранее установленное значения типа отмены потока, которые могут принимать значения
PTHREAD_CANCEL_ASYNCHRONOUS
(асинхронный по отмене поток) либо
PTHREAD_CANCEL_DEFERRED
(синхронный по отмене поток). Значением по умолчанию, устанавливаемым при создании потока, является
PTHREAD_CANCEL_DEFERRED
, хотя предписываемым POSIX умолчанием является
PTHREAD
_CANCEL_ASYNCHRONOUS.
Обе рассмотренные функции установок [23]параметров отмены при успешном выполнении возвращают значение EOK.
Итак, действия потока на запрос его завершения будут определяться текущей комбинацией двух установленных для него параметров: состоянием и типом отмены.
Теперь о том, чем же отличается отмена асинхронно и синхронно завершаемых потоков. Поток с асинхронным типом отмены (установленный с
PTHREAD_CANCEL_ASYNCHRONOUS
) может быть отменен в любой произвольный момент времени, то есть он всегда «свободен» для отмены и отмена производится немедленно. Поток с синхронным типом отмены (установленный с
PTHREAD_CANCEL_DEFERRED
) может быть остановлен только в тех точках выполнения потока, когда ему «удобно», и соответствующие места в программе называются точками отмены. При поступлении запроса на отмену такого потока (после выполнения извне
pthread_cancel()
) запрос помещается в очередь, а процесс отмены активизируется только после того, как отменяемый поток в ходе своего выполнения достигнет очередной точки отмены. Как определяются (создаются) точки отмены в коде потока? Для этого служит функция:
void pthread_testcancel(void);
Каждый вызов
pthread_testcancel()
тестирует очередь поступивших запросов на отмену на предмет наличия запросов, и если таковой запрос есть, процесс отмены активизируется. Если в коде отсутствуют вызовы
pthread_testcancel()
, то в нем практически отсутствуют точки отмены и поток становится неотменяемым (подобно установке его состояния отмены в
PTHREAD_CANCEL_DISABLE
). Поэтому при выполнении длительных вычислений функцию
pthread_testcancel()
следует периодически вызывать в потоковой функции в тех точках, где потенциальная отмена потока не опасна.
(
Очень важно!) Достаточно много библиотечных функций могут сами устанавливать точки отмены. Более того, такие функции могут косвенно вызываться из других функций в программе и тем самым неявно устанавливать точки отмены. Информацию о таких функциях следует искать в справочной man-странице по функции
pthread_testcancel()
. В результате этого эффекта можно получить отмену потока не в той точке, которую вы считаете безопасной и которую явно отмечаете вызовом
pthread_testcancel()
, а ранее этой точки — когда будет вызвана одна из таких функций. А это, очевидно, вовсе не то, на что вы рассчитывали!
Если состояние отмены потока, как это описывалось ранее, установлено в
PTHREAD_CANCEL_DISABLE
, то никакая расстановка точек отмены не имеет эффекта и поток остается неотменяемым.
Покажем, как могут быть использованы все эти предосторожности в коде функции потока, чтобы сделать код безопасным с позиции возможной асинхронной отмены потока извне:
void* function(void* data) {
int state;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
// ... здесь выполняется инициализация ...
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
pthread_setcancelstate(&state, NULL);
while (true) {
struct blockdata *blk = new blockdata;
// ... обработка блока данных blk ...
delete blk;
pthread_testcancel();
}
}
...