Книга: Основы программирования в Linux
Отмена потока
Разделы на этой странице:
Отмена потока
Иногда требуется, чтобы один поток попросил другой завершиться досрочно способом, очень похожим на отправку ему сигнала. Сделать это можно с помощью потоков и параллельно с помощью обработки сигнала; у потоков появляется возможность изменить свое поведение, когда их просят завершиться.
Давайте сначала рассмотрим функцию для создания запроса на завершение потока.
#include <pthread.h>
int pthread_cancel(pthread_t thread);
Она достаточно проста: имея идентификатор потока, вы можете запросить его аннулирование. На приемном конце запроса на отмену все немного сложнее, но не слишком. Поток может установить состояние отмены с помощью функции pthread_setcancelstate
.
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
Первый параметр равен либо значению PHTREAD_CANCEL_ENABLE
, позволяющему получать запросы на отмену, либо PTHREAD_CANCEL_DISABLE
, заставляющему игнорировать подобные запросы. Указатель oldstate
дает возможность получить предыдущее состояние. Если оно вас не интересует, можно просто передать в этом параметре NULL
. Если запросы на отмену принимаются, есть второй уровень управления, принимаемый потоком, — тип отмены, который задается функцией pthread_setcanceltype
.
#include <pthread.h>
int pthread_setcanceltype(int type, int *oldtype);
Тип отмены может принимать одно из следующих значений: PTHREAD_CANCEL_ASYNCHRONOUS
, заставляющее обрабатывать запросы на отмену немедленно, и PTHREAD_CANCEL_DEFERRED
, заставляющее запросы на отмену ждать, пока поток не выполнит одну из следующих функций: pthread_join
, pthread_cond_wait
, pthread_cond_timedwait
, pthread_testcancel
, sem_wait
или sigwait
.
Мы не описываем все эти функции в данной главе, поскольку, как правило, не все они нужны. Когда они понадобятся, вы сможете найти дополнительную информацию на страницах интерактивного справочного руководства.
Примечание
В соответствии со стандартом POSIX системные вызовы, способные задерживать выполнение, такие как read
, wait
и т.д., должны также быть точками отмены потока. Во время написания книги поддержка этого стандарта в ОС Linux представлялась незавершенной. Но кое-какая работа была проделана, скажем, некоторые задерживающие вызовы, такие как sleep
, на самом деле допускают отмену. Для того чтобы обезопасить себя, добавляйте вызовы pthread_testcancel
в программный код, который по вашим расчетам может быть отменен.
Параметр oldtype
позволяет получить предыдущее состояние, если оно вас не интересует, можно передать NULL
. По умолчанию потоки запускаются с состоянием отмены, равным PTHREAD_CANCEL_ENABLE
, и типом отмены — PTHREAD_CANCEL_DEFERRED
.
Выполните упражнение 12.7.
Упражнение 12.7. Отмена потока
Программа thread7.c — ещё один потомок программы thread1.с. На этот раз основной поток отправляет запрос на отмену потока, который он создал.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void *thread_function(void *arg);
int main() {
int res;
pthread_t a_thread;
void *thread_result;
res = pthread_create(&a_thread, NULL, thread_function, NULL);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
sleep(3);
printf("Canceling thread...n");
res = pthread_cancel(a_thread);
if (res != 0) {
perror("Thread cancelation failed");
exit(EXIT_FAILURE);
}
printf("Waiting for thread to finish...n");
res = pthread_join(a_thread, &thread_result);
if (res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
int i, res;
res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (res != 0) {
perror("Thread pthread_setcancelstate failed");
exit(EXIT_FAILURE);
}
res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
if (res != 0) {
perror{"Thread pthread_setcanceltype failed");
exit(EXIT_FAILURE);
}
printf("thread_function is runningn");
for(i = 0; i < 10; i++) {
printf("Thread is still running (%d)...n", i);
sleep(1);
}
pthread_exit(0);
}
Когда вы выполните эту программу, то увидите следующий вывод, демонстрирующий отмену потока:
$ ./thread7
thread_function is running
Thread is still running (0)...
Thread is still running (1)...
Thread is still running (2)...
Canceling thread...
Waiting for thread to finish...
$
Как это работает
После того как новый поток был создан обычным способом, основной поток засыпает (чтобы дать новому потоку время для запуска) и затем отправляет запрос на отмену потока.
sleep(3);
printf("Cancelling thread...n");
res = pthread_cancel(a_thread);
if (res != 0) {
perror("Thread cancelation failed");
exit(EXIT_FAILURE);
}
В созданном потоке вы сначала задаете состояние отмены, чтобы разрешить отмену потока:
res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (res != 0) {
perror("Thread pthread_setcancelstate failed");
exit(EXIT_FAILURE);
}
Далее вы задаете тип отмены PTHREAD_CANCEL_DEFERRED
:
res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
if (res != 0) {
perror("Thread pthread_setcanceltype failed");
exit(EXIT_FAILURE);
}
И в конце поток ждет отмену:
for (i = 0; i < 10; i++) {
printf("Thread is still running (%d)...n", i);
sleep(1);
}
- Безопасная отмена выполнения потоков
- Отмена выполнения операций перекрывающегося ввода
- 4.2. Отмена потока
- 8.5. Отмена выполнения потоков
- Асинхронный сервер и отмена выполняющихся запросов
- Применение основного потока
- Пример использования фонового потока для выполнения отдельной задачи
- Листинг 5.8. (dup2.c) Перенаправление выходного потока канала с помощью функции dup2()
- Отмена ошибочных действий
- Пример: функция readline, использующая собственные данные потока
- Вдохновение от потока идей
- Создание потока