Главная страница Взаимодействие нетривиальных процессов 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 осуществляются независимо друг от друга. Возможны четыре ситуации:
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |