Книга: UNIX: взаимодействие процессов

Досрочное завершение клиента

Досрочное завершение клиента

Посмотрим, каким образом процедура сервера получает уведомление о досрочном завершении клиента. Пpoгрaммa-клиeнт приведена в листинге 15.25.

Листинг 15.25. Клиент, досрочно завершающий работу после вызова door_call

//doors/clientintr4.c
1  #include "unpipc.h"
2  int
3  main(int argc, char **argv)
4  {
5   int fd;
6   long ival, oval;
7   door_arg_t arg;
8   if (argc != 3)
9    err_quit("usage: clientintr4 <server-pathname> <integer-value>");
10  fd = Open(argv[1], O_RDWR); /* открываем дверь */
11  /* подготовка аргументов и указателя на результаты */
12  ival = atol(argv[2]);
13  arg.data_ptr = (char*)&ival; /* аргументы */
14  arg.data_size = sizeof(long); /* размер аргументов */
15  arg.desc_ptr = NULL;
16  arg.desc_num = 0;
17  arg.rbuf = (char*)&oval; /* возвращаемые данные */
18  arg.rsize = sizeof(long); /* размер возвращаемых данных */
19  /* вызов процедуры сервера и вывод результата */
20  alarm(3);
21  Door_call(fd, &arg);
22  printf("result: %ldn", oval);
23  exit(0);
24 }

20 Единственное изменение заключается в добавлении вызова alarm(3) перед door_call. Эта функция приводит к отправке сигнала SIGALRM через три секунды после вызова, но, поскольку мы его не перехватываем, это приводит к завершению процесса. Поэтому клиент завершится до возврата из door_call, потому что в процедуру сервера вставлена шестисекундная пауза.

В листинге 15.26 приведен текст процедуры сервера и обработчик отмены потока.

Листинг 15.26. Процедура сервера, обрабатывающая досрочное завершение клиента

//doors/serverintr4.с
1  #include "unpipc.h"
2  void
3  servproc_cleanup(void *arg)
4  {
5   printf("servproc cancelled, thread id %ldn", pr_thread_id(NULL));
6  }
7  void
8  servproc(void *cookie, char *dataptr, size_t datasize,
9   door_desc_t *descptr, size_t ndesc)
10 {
11  int oldstate, junk;
12  long arg, result;
13  Pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
14  pthread_cleanup_push(servproc_cleanup, NULL);
15  sleep(6);
16  arg = *((long*)dataptr);
17  result = arg * arg;
18  pthread_cleanup_pop(0);
19  Pthread_setcancelstate(oldstate, &junk);
20  Door_return((char*)&result, sizeof(result), NULL, 0);
21 }

Вспомните, что мы говорили об отмене выполнения потока в разделе 8.5 и в связи с листингом 15.18. Когда система обнаруживает завершение клиента в процессе выполнения серверной процедуры, потоку, обрабатывающему запрос этого клиента, отправляется запрос на отмену:

? если поток отключил возможность отмены, ничего не происходит и поток выполняется до завершения (вызов door_return), а результаты сбрасываются;

? если возможность отмены включена, вызываются обработчики отмены потока, а затем он завершает работу.

В тексте процедуры сервера мы сначала вызвали pthread_setcancelstate для включения возможности отмены потока, потому что по умолчанию при создании новых потоков библиотекой возможность их отмены отключается. Эта функция сохраняет текущее состояние потока в переменной oldstate, и мы восстанавливаем его в конце функции. Затем мы вызываем pthread_cleanup_push для регистрации нашего обработчика отмены servproc_cleanup. Эта функция только выводит идентификатор отмененного потока, но вообще она может выполнять все необходимое для корректного завершения процедуры сервера (разблокировать исключения и т. п.). После возвращения из обработчика поток завершается.

В текст процедуры сервера мы добавляем 6-секундную паузу, чтобы клиент мог успешно завершить работу в вызове door_call.

Запустив клиент дважды, мы увидим сообщение интерпретатора Alarm clock при завершении процесса сигналом SIGALRM:

solaris % clientintr4 /tmp/door4 44
Alarm Clock
solaris % clientintr4 /tmp/door4 44
Alarm Clock

Посмотрим, что при этом выводит сервер. Каждый раз при досрочном завершении клиента поток процедуры сервера действительно отменяется и вызывается обработчик отмены потока: 

solaris % serverintr4 /tmp/door4
servproc canceled, thread id 4
servproc canceled, thread id 5

Цель, с которой мы вызываем программу-клиент дважды, — показать, что после завершения потока с идентификатором 4 библиотека создает новый поток (с идентификатором 5) для обработки второго запроса клиента.

Оглавление книги


Генерация: 0.327. Запросов К БД/Cache: 2 / 0
поделиться
Вверх Вниз