Обработчики-очистители выполняют всю необходимую работу по восстановлению значений переменных, такую как разблокирование взаимных исключений и семафоров, которые могли быть заблокированы данным потоком.
Аргумент
ПРИМЕЧАНИЕ
Мы снова встретимся с проблемой отмены выполнения потоков в связи с листингом 15.26, где может произойти отмена выполнения сервера с дверьми при завершении работы клиента в процессе обработки вызванной им процедуры.
Пример
Легче всего продемонстрировать проблему нашей реализации из предыдущего раздела с помощью примера. На рис. 8.1 изображена временная диаграмма выполнения нашей программы, а текст самой программы приведен в листинге 8.9.
Рис. 8.1. Временная диаграмма выполнения программы из листинга 8.9
10-13 Создаются два потока, первый из которых выполняет функцию thread1, а второй — thread2. После создания первого делается пауза длительностью в одну секунду, чтобы он успел заблокировать ресурс на чтение.
14-23 Мы ожидаем завершения работы второго потока и проверяем, что его статус имеет значение PTHREAD_CANCEL. Затем мы ждем завершения работы первого потока и проверяем, что его статус представляет собой нулевой указатель. Затем мы выводим значение трех счетчиков в структуре pthread_rwlock_t и уничтожаем блокировку.
//my_rwlock_cancel/testcancel.с
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3 pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
4 pthread_t tid1, tid2;
5 void *thread1(void *), *thread2(void *);
6 int
7 main(int argc, char **argv)
8 {
9 void *status;
10 Set_concurrency(2);
11 Pthread_create(&tid1, NULL, thread1, NULL);
12 sleep(1); /* даем первому потоку возможность получить блокировку */
13 Pthread_create(&tid2, NULL, thread2, NULL);
14 Pthread_join(tid2, &status);
15 if (status != PTHREAD_CANCELED)
16 printf("thread2 status = %p\n", status);
17 Pthread_join(tid1, &status);
18 if (status != NULL)
19 printf("thread1 status = %p\n", status);
20 printf("rw_refcount = %d, rw_nwaitreaders = %d, rw_nwaitwriters = %d\n",
21 rwlock.rw_refcount, rwlock.rw_nwaitreaders,
22 rwlock.rw_nwaitwriters);
23 Pthread_rwlock_destroy(&rwlock);
24 exit(0);
25 }
26 void *
27 thread1(void *arg)
28 {
29 Pthread_rwlock_rdlock(&rwlock);
30 printf("thread1() got a read lock\n");
31 sleep(3); /* даем второму потоку возможность заблокироваться при вызове pthread_rwlock_wrlock() */
32 pthread_cancel(tid2);
33 sleep(3);
34 Pthread_rwlock_unlock(&rwlock);
35 return(NULL);
36 }
37 void *
38 thread2(void *arg)
39 {
40 printf("thread2() trying to obtain a write lock\n"):
41 Pthread_rwlock_wrlock(&rwlock);
42 printf("thread2() got a write lock\n"); /* не будет выполнено */
43 sleep(1);
44 Pthread_rwlock_unlock(&rwlock);
45 return(NULL);
46 }