Чтение онлайн

ЖАНРЫ

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

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

Шрифт:

thread id 4, arg = 33

Запустим теперь три экземпляра клиента одновременно в фоновом режиме:

solaris % client6 /tmp/door6 44 &client6 /tmp/door6 55 &client6 /tmp/door6 66 &

[2] 4919

[3] 4920

[4] 4921

solaris % result: 1936

result: 4356

result: 3025

Посмотрев на вывод сервера, мы увидим, что было создано два новых потока (с идентификаторами 6 и 7) и потоки 4, 5

и 6 обслужили три запроса от клиентов:

thread id 4, arg = 44

my_thread: created server thread 6

thread id 5, arg = 66

my_thread: created server thread 7

thread id 6, arg = 55

15.10. Функции door_bind, door unbind и door_revoke

Рассмотрим еще три функции, дополняющие интерфейс дверей:

#include <door.h>

int door_bind(int fd);

int door_unbind(void);

int door_revoke(int fd);

/* Всe три возвращают 0 в случае успешного завершения, –1 – в случае ошибки */

Функция door_bind впервые появилась в листинге 15.18. Она связывает вызвавший ее поток с частным пулом сервера, относящимся к двери с дескриптором fd. Если вызвавший поток уже подключен к какой-либо другой двери, производится его неявное отключение.

Функция door_unbind осуществляет явное отключение потока от текущего пула, к которому он подключен.

Функция door_revoke отключает доступ к двери с дескриптором fd. Дескриптор двери может быть отменен только процессом, создавшим эту дверь. Все вызовы через эту дверь, находящиеся в процессе выполнения в момент вызова этой функции, будут благополучно завершены.

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

В наших примерах до настоящего момента предполагалось, что в процессе работы клиента и сервера не возникает непредусмотренных ситуаций. Посмотрим, что произойдет, если у клиента или сервера возникнут ошибки. В случае если клиент и сервер являются частями одного процесса (локальный вызов процедуры на рис. 15.1), клиенту не нужно беспокоиться о возникновении ошибок на сервере, и наоборот. Однако если клиент и сервер находятся в различных процессах, нужно учесть возможность досрочного завершения одного из них и предусмотреть способ уведомления второго об этом событии. Об этом нужно заботиться вне зависимости от того, находятся ли клиент и сервер на одном узле или нет.

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

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

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

//doors/serverintr1.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 pthread_exit(NULL); /*
посмотрим, что произойдет с клиентом */

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

9 result = arg * arg;

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

11 }

Оставшаяся часть сервера не претерпевает изменений по сравнению с листингом 15.2, а программу-клиент мы берем из листинга 15.1.

Запустив клиент, мы увидим, что вызов door_call возвращает ошибку EINTR, если процедура сервера завершается досрочно:

solaris % clientintr1 /tmp/door1 11

door_call error: Interrupted system call

Непрерываемость системного вызова door_call

Документация на door_call предупреждает, что эта функция не предполагает возможности перезапуска (библиотечная функция door_call делает системный вызов с тем же именем). Мы можем убедиться в этом, изменив процедуру сервера таким образом, чтобы она делала паузу в 6 секунд перед возвращением, что показано в листинге 15.21.

Листинг 15.21. Процедура сервера делает паузу в 6 секунд

//doors/serverintr2.с

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 sleep(6); /* клиент получает сигнал SIGCHLD */

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

9 result = arg * arg;

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

11 }

Изменим теперь клиент из листинга 15.2: установим обработчик сигнала SIGCHLD, добавив порождение процесса и завершение порожденного процесса через 2 секунды. Таким образом, через 2 секунды после вызова door_call дочерний процесс завершит работу, а родительский перехватит сигнал SIGCHLD и произойдет возврат из обработчика сигнала, прерывающий системный вызов door_call. Текст программы-клиента показан в листинге 15.22.

Листинг 15.22. Клиент, перехватывающий сигнал SIGCHLD

//doors/clientintr2.c

1 #include "unpipc.h"

2 void

3 sig_chld(int signo)

4 {

5 return; /* просто прерываем door_call */

6 }

7 int

8 main(int argc, char **argv)

9 {

10 int fd;

11 long ival, oval;

12 door_arg_t arg;

Поделиться с друзьями: