В качестве дополнительного удобства все обработчики для очистки ресурсов, которые не сработали, выполняются автоматически, если поток завершается с помощью вызова pthread_exit() (это не касается ситуаций, когда для завершения используется инструкция return).
В листинге 32.2 представлен простой пример использования обработчика для освобождения ресурсов. Главная программа создает поток
Затем поток входит в цикл и ждет, когда условная переменная cond получит уведомление
• Если аргумент командной строки отсутствует, поток отменяется функцией main()
• Если аргумент командной строки был предоставлен, условная переменная получает уведомление
Главная программа присоединяет завершенный поток
Листинг 32.2. Использование обработчиков для освобождения ресурсов
threads/thread_cleanup.c
#include
#include "tlpi_hdr.h"
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static int glob = 0; /* Предикат */
static void /* Освобождаем память по адресу 'arg' и открываем мьютекс */
cleanupHandler(void *arg)
{
int s;
printf("cleanup: freeing block at %p\n", arg);
printf("cleanup: unlocking mutex\n");
if (s!= 0)
errExitEN(s, "pthread_mutex_unlock");
}
static void *
threadFunc(void *arg)
{
int s;
void *buf = NULL; /* Буфер, выделенный потоком */
printf("thread: allocated memory at %p\n", buf);
if (s!= 0)
errExitEN(s, "pthread_mutex_lock");
while (glob == 0) {
if (s!= 0)
errExitEN(s, "pthread_cond_wait");
}
printf("thread: condition wait loop completed\n");
return NULL;
}
int
main(int argc, char *argv[])
{
pthread_t thr;
void *res;
int s;
if (s!= 0)
errExitEN(s, "pthread_create");
sleep(2); /* Даем потоку шанс начать работу */
if (argc == 1) { /* Отменяем поток */
printf("main: about to cancel thread\n");
if (s!= 0)
errExitEN(s, "pthread_cancel");
} else { /* Уведомляем условную переменную */
printf("main: about to signal condition variable\n");
glob = 1;
if (s!= 0)
errExitEN(s, "pthread_cond_signal");
}
if (s!= 0)
errExitEN(s, "pthread_join");
if (res == PTHREAD_CANCELED)
printf("main: thread was canceled\n");
else
printf("main: thread terminated normally\n");
exit(EXIT_SUCCESS);
}
threads/thread_cleanup.c
Если запустить программу из листинга 32.2 без аргументов командной строки, функция main() сделает вызов pthread_cancel(), после чего автоматически выполнится обработчик очистки ресурсов, и мы увидим следующее:
$ ./thread_cleanup
thread: allocated memory at 0x804b050
main: about to cancel thread
cleanup: freeing block at 0x804b050
cleanup: unlocking mutex
main: thread was canceled
Если запустить программу с аргументом командной строки, функция main() присвоит glob значение 1 и уведомит об этом условную переменную, после чего вызов pthread_cleanup_pop() приведет к выполнению обработчика очистки ресурсов, и мы увидим следующее:
$ ./thread_cleanup s
thread: allocated memory at 0x804b050
main: about to signal condition variable
thread: condition wait loop completed
cleanup: freeing block at 0x804b050
cleanup: unlocking mutex
main: thread terminated normally
Если сделать поток асинхронно отменяемым (тип отмены PTHREAD_CANCEL_ASYNCHRONOUS), его можно будет отменить в любой момент (то есть в любом машинном коде); это процедура не задерживается до достижения потоком следующей точки отмены.