Читать «UNIX: взаимодействие процессов» онлайн - страница 255

Уильям Ричард Стивенс

Отключение отмены потока

23 При создании нового потока вызовом pthread_create его отмена по умолчанию разрешена. Если отмена потока разрешена и клиент прерывает вызов door_call в процессе его выполнения (что мы продемонстрируем в листинге 15.26), вызываются обработчики отмены потока, после чего он завершается. Если отмена потока отключена (как это делаем мы) и клиент прерывает работу в вызове door_call, процедура сервера спокойно завершает работу (поток не завершается), а результаты door_return просто сбрасываются. Поскольку серверный поток завершается, если происходит отмена потока, и поскольку процедура сервера может в этот момент выполнять какие-то действия (возможно, с заблокированными семафорами или блокировками), библиотека дверей на всякий случай отключает отмену всех создаваемых ею потоков. Если нам нужно, чтобы процедура сервера отменялась при досрочном завершении работы клиента, для этого потока следует включить возможность отмены и приготовиться обработать такую ситуацию.

ПРИМЕЧАНИЕ

Обратите внимание, что область выполнения PTHREAD_SCOPE_SYSTEM и неприсоединенность потока указываются как атрибуты при создании потока. А отмена потока может быть отключена только в процессе выполнения потока. Таким образом, хотя мы и отключаем отмену потока, он сам может ее включить и выключить тогда, когда потребуется.

Связывание потока с дверью

24 Вызов door_bind позволяет добавить поток к пулу, связанному с дверью, дескриптор которой передается door_bind в качестве аргумента. Поскольку для этого нам нужно знать дескриптор двери, в этой версии сервера он является глобальной переменной.

Делаем поток доступным клиенту

25 Мы делаем поток доступным клиенту вызовом door_return с двумя нулевыми указателями и нулевыми значениями длин буферов в качестве аргументов.

Процедура сервера приведена в листинге 15.19. Она идентична программе из листинга 15.6.

Листинг 15.19. Процедура сервера

//doors/server6.c

1  #include "unpipc.h"

2  void

3  servproc(void *cookie, char *dataptr, size_t datasize,

4   door_desc_t *descptr, size_t ndesc)

5  {

6   long arg, result;

7   arg = *((long *) dataptr);

8   printf("thread id %ld, arg = %ld\n", pr_thread_id(NULL), arg);

9   sleep(5);

10  result = arg * arg;

11  Door_return((char *)&result, sizeof(result), NULL, 0);

12 }

Чтобы продемонстрировать работу программы, запустим сервер:

solaris % server6 /tmp/door6

my_thread: created server thread 4

После запуска сервера и вызова door_create процедура создания сервера запускается в первый раз, хотя клиент мы еще не запустили. При этом создается первый поток, ожидающий запроса от первого клиента. Затем мы запускаем клиент три раза подряд: