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

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

16 /* ОК, возвращаем дескриптор */

17 descd data,d desc.d descriptor = fd;

18 desc,d~attr-ibutes = DOOR DESCRIPTOR;

19 Door return(NULL, 0, &desc, 1);

20 }

21 }

Открытие файла для клиента

9-14 Мы завершаем полное имя файла клиента нулем и делаем попытку открыть этот файл вызовом open. Если возникает ошибка, сообщение о ней возвращается клиенту.

Успешное открытие файла

15-20 Если файл был успешно открыт, клиенту возвращается только его дескриптор.

Запустим сервер и укажем ему имя двери /tmp/fdl, а затем запустим клиент:

Solaris X clientfdl /tmp/fdl

/etc/shadow

/etc/shadow; cant open. Permission denied Solaris X clientfdl /tmp/fdl

/no/such/file

/no/such/file: cant open. No such file or directory

solar-is X clientfdl /tmp/fdl

/etc/ntp.conf фаЯп из двух строк

multicastclient 224,0.1,1

driftfile /etc/ntp,drift

В первых двух слзд1аях мы указываем имя файла, приводящее к возврату сообщения об ошибке. В третий раз сервер передает клиенту дескриптор файла из двух строк, который благоползд1НО выводится.

ПРИМЕЧАНИЕ-

Существует проблема, связанная с передачей дескриптора через дверь. Чтобы она проявилась в нашем примере, достаточно добавить вызов printf к процедуре сервера сразу после успешного вызова open. Вы увидите, что значение дескриптора каждый раз увеличивается на единицу. Проблема в том, что сервер не закрывает дескрипторы после передачи их клиенту. Сделать это, вообще говоря, нелегко. Логично было бы выполнять закрытие дескриптора после возврата из door return, после успешной отправки дескриптора клиенту, но возврата из door return не происходит! Если бы мы использовали sendmsg для передачи дескриптора через доменный сокет Unix или ioctl для передачи дескриптора через канал в SVR4, мы могли бы закрыть его после возврата из sendmsg или ioctl. Однако с дверьми все по-другому, поскольку возврата из функции door return не происходит. Единственный способ обойти проблему заключается в том, что процедура сервера должна запоминать все открытые дескрипторы и закрывать их некоторое время спустя, что несколько запутывает код.

Эта проблема должна быть исправлена в Solaris 2,7 добавлением атрибута DOOR RELEASE. Отправитель устанавливает поле d attributes равным DOOR DESCRIPTOR DOOR RELEASE, что говорит системе о необходимости закрывать дескриптор после передачи его клиенту.



15.9. Функция door server create

в листинге 15.6 мы показали, что библиотека дверей автоматически создает новые потоки для обслуживания запросов клиентов по мере их поступления. Они создаются библиотекой как неприсоединенные потоки (detached threads) с размером стека потока по умолчанию, с отключенной возможностью отмены потока (thread cancellation) и с маской сигналов и классом планирования (scheduling class), унаследованными от потока, вызвавшего cloor create. Если мы хотим изменить какой-либо из этих параметров или хотим самостоятельно работать с пулом потоков сервера, можно воспользоваться функцией cloor server create и указать нашу собственную процедуру создания сервера: finclude <door.h>

typedef void Door create proc(door info t *):

Door create proc *door server create(Door create proc *proc):

/* Возвращает указатель на предыдущую процедуру создания сервера */

Как и при объявлении cloor create в разделе 15.3, мы используем оператор typedef для упрощения прототипа библиотечной функции. Наш новый тип данных определяет процедуру создания сервера как принимающую один аргумент (указатель на структуру типа door i nf o t) и ничего не возвращающую (voi d). При вызове door server create аргументом является указатель на нашу процедуру создания сервера, а возвращается указатель на предыдущую процедуру создания сервера.

-> servproc () {

вызов myjhread при запуске очередного нового потока

door return {); }

my thread {) {

door bind {); door return {);

логически

каждый поток

продолжает

выполнение

с servproc

при поступлении

нового клиента

регистрация функции my create

-> my create {) {

pthread create { , myjhead,);

main () {

.регистрация servproc

door server create {my create); fd = door create (servproc,);

в качестве процедуры сервера для данной двери, вызов my create для создания нового потока

Рис. 15.5. Четыре функции в процессе-сервере

у процедура сервера

функция,

вызываемая

каждым

потоком

сервера

процедура } создания сервера



Наша процедура создания сервера вызывается при возникновении необходимости создания нового потока для обслуживания запроса клиента. Информация о том, какой из процедур сервера требуется новый поток, передается в структуре cloor i nf o t, адрес которой принимается процедурой создания сервера. Поле cli proc содержит адрес процедуры сервера, а поле cli clata содержит указатель на аргументы, передаваемые процедуре сервера при вызове.

Проще всего изучить происходящее на примере. Программа-клиент не претерпевает никаких изменений по сравнению с листингом 15.1. В программу-сервер добавляются две новые функции помимо процедуры сервера и функции mai п. На рис. 15.5 приведена схема сервера с четырьмя функциями и последовательностью их регистрации и вызова.

В листинге 15.17 приведен текст функции main сервера.

Листинг 15.17. Функция main для примера с управлением пулом потоков

doors/server6.c

42 int

43 mainCint argc, char **argv)

44 {

45 if (argc != 2)

46 err quit( usage: server6 <server-pathname> );

47 Door server create(my create):

48 /* создание дескриптора двери и связывание его с именем */

49 Pthread mutexJock(&fdlock):

50 fd = Door create(servproc. NULL, DOOR PRIVATE);

51 Pthread mutex unlock(&fdlock):

52 unlink(argv[l]):

53 Close(Open(argv[l]. 0 CREAT 0 RDWR. FILE MODE)):

54 FattachCfd. argvEl]);

55 /* servprocO обслуживает запросы клиентов */

56 for ( : ; )

57 pauseO:

58 }

По сравнению с листингом 15.2 было внесено четыре изменения:

1. Убрано объявление дескриптора двери f d (теперь это глобальная переменная, описанная в листинге 15.18).

2. Вызов door create защищен взаимным исключением (также описанным в листинге 15.18).

3. Вызов door server create делается перед созданием двери, при этом указывается процедура создания сервера (my thread, которая, будет показана позже).

4. В вызове door create последний аргумент (атрибуты) имеет значение 000R PRIVATE вместо 0. Это говорит библиотеке о том, что данная дверь будет иметь собственный пул потоков, называемый частным пулом сервера.

Задание процедуры создания сервера с помощью door server create и выделение частного пула сервера с помощью DOOR PRIVATE осуществляются независимо друг от друга. Возможны четыре ситуации:



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.
Копирование материалов разрешено исключительно при условии цититирования.