Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 [ 132 ] 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

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

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

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

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

doors/cl1ent1ntr4.c

1 #lnclude unpipc.h

2 Int

3 ma1n(int argc, char **argv)

5 Int fd;

6 long Ival, oval;

7 door arg t arg;

8 If (argc != 3)

9 err qu1t( usage; cl1ent1ntr4 <server-pathname> <lnteger-value> ):

10 fd = Open(argv[l]. 0 RDWR); /* открываем дверь */

11 /* подготовка аргументов и указателя на результаты */

12 Ival = atol(argv[2]);

13 arg.data ptr = (char *) &1val: /* аргументы */

14 arg.data s1ze = slzeof(long); /* размер аргументов */

15 arg.desc ptr = NULL;

16 arg.desc num = 0;

17 arg.rbuf = (char *) &oval; /* возвращаемые данные */

18 arg.rsize = slzeof(long); /* размер возвращаемых данных */

19 /* вызов процедуры сервера и вывод результата */

20 alarm(3);

21 Door call(fd, &arg);

22 printf( result; ld\n , oval);

23 exlt(O);

24 }

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

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

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

doors/serverintr4.с

1 #1nclude unpipc.h

2 продолжение



Листинг 15.26 (продолжение)

3 servproc cleanup(vo-id *arg)

5 printf( servproc cancelled, thread id lld\n . pr thread 1d(NULL));

7 void

8 servproc(vo1d *cook1e, char *dataptr, s1ze t datasize,

9 door desc t *descptr, slze 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 cleanupj)op(0);

19 Pthread setcancelstate(oldstate, &junk);

20 Door return((char *) &result, sizeof(result), NULL, 0);

21 }

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

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

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

В тексте процедуры сервера мы сначала вызвали pthread setcancel state для включения возможности отмены потока, потому что по умолчанию при создании новых потоков библиотекой возможность их отмены отключается. Эта функция сохраняет текущее состояние потока в переменной о1 dstate, и мы восстанавливаем его в конце функции. Затем мы вызываем pthread cleanup push для регистрации нашего обработчика отмены servproccleanup. Эта функция только выводит идентификатор отмененного потока, но вообще она может выполнять все необходимое для корректного завершения процедуры сервера (разблокировать исключения и т. п.). После возвращения из обработчика поток завершается.

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

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

Solaris % clientintr4 /tmp/door4 44

Alarm Clock

Solaris % clientintr4 /tmp/door4 44

Alarm Clock

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



Solaris X serverintr4 /tmp/door4

servproc canceled, thread id 4 servproc canceled, thread id 5

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

15.12. Резюме

Интерфейс дверей позволяет вызывать процедуры в других процессах на том же узле. В следующей главе мы обсудим возможность удаленного вызова процедур в процессах на других узлах.

Основные функции этого интерфейса просты в работе и использовании. Сервер вызывает doorcreate для создания двери и связывания ее с процедурой сервера, а затем вызывает fattach для сопоставления этой двери и имени файла в файловой системе. Клиент вызывает open для этого имени файла и затем может вызвать doorcall для вызова процедуры сервера. Возврат из процедуры сервера осуществляется вызовом door return.

Обычно разрешения для двери проверяются только один раз - при ее открытии вызовом open. Проверяются идентификаторы пользователя и группы клиента (и полного имени файла). Одной из полезных функций дверей (по сравнению с другими средствами IPC) является возможность получения информации о клиенте в процессе работы (его действующего и реального идентификаторов). Это может использоваться сервером для принятия решения о предоставлении услуг данному клиенту.

Двери предоставляют возможность передачи дескрипторов от клиента серверу и обратно. Это достаточно мощное средство, поскольку дескрипторы в Unix дают возможность обращаться ко множеству объектов (файлам, сокетам или XTI, дверям).

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

Упражнения

1. Сколько байтов информации передается при вызове door cal 1 от клиента серверу?

2. Есть ли необходимость вызывать fstat для проверки типа дескриптора в листинге 15.3? Уберите этот вызов и посмотрите, что произойдет.

3. В документации Solaris 2.6 для вызова sleep О говорится, что выполнение текущего процесса приостанавливается . Почему при этом библиотека дверей имеет возможность создать новые потоки в листинге 15.6?



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 [ 132 ] 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.