Главная страница Взаимодействие нетривиальных процессов 4 door desc t *descptr. size t ndesc) 6 long arg. result: 7 arg = *((long *) dataptr): 8 printf( thread id ld. arg = ld\n , pr thread id(NULL), arg): 9 sleep(5): 10 result = arg * arg: 11 Door return((char *) &result. sizeofCresult). NULL. 0): 12 } Чтобы продемонстрировать работу программы, запустим сервер: Solaris X servers /tmp/door6 my thread: created server thread 4 После запуска сервера и вызова doorcreate процедура создания сервера запускается в первый раз, хотя клиент мы еще не запустили. При этом создается первый поток, ожидающий запроса от первого клиента. Затем мы запускаем клиент три раза подряд: Solaris X clients /tmp/door6 11 result; 121 Solaris X clients /tmp/doorS 22 result: 484 Solaris X clients /tmp/doorS 33 result: 1089 Посмотрим, что при этом выводит сервер. При поступлении первого запроса клиента создается новый поток (с идентификатором потока 5), а поток с номером 4 обслуживает все запросы клиентов. Библиотека дверей всегда держит один лищний поток наготове: my thread: created server thread 5 thread id 4. arg = 11 thread id 4. arg = 22 thread id 4. arg = 33 Запустим теперь три экземпляра клиента одновременно в фоновом режиме: Solaris X clients /tmp/doorS 44 & clients /tmp/doorS SS & clients /tmp/doorS 66 & [2] 4919 [3] 4920 [4] 4921 Solaris X 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 Рассмотрим еще три функции, дополняющие интерфейс дверей: #inc1ude <door.h> 1nt door b1nd(int fd): int door unb1nd(void): int door revoke(int fd): /* See три возвращают О в случае успешного завершения, -1 - в случае ошибки */ Функция cloor bincl впервые появилась в листинге 15.18. Она связывает вызвавший ее поток с частным пулом сервера, относящимся к двери с дескриптором f d. Если вызвавший поток уже подключен к какой-либо другой двери, производится его неявное отключение. Функция door unbi nd осуществляет явное отключение потока от текущего пула, к которому он подключен. Функция door revoke отключает доступ к двери с дескриптором fd. Дескриптор двери может быть отменен только процессом, создавшим эту дверь. Все вызовы через эту дверь, находящиеся в процессе выполнения в момент вызова этой функции, будут благополучно завершены. 15.11. Досрочное завершение клиента или сервера в наших примерах до настоящего момента предполагалось, что в процессе работы клиента и сервера не возникает непредусмотренных ситуаций. Посмотрим, что произойдет, если у клиента или сервера возникнут ошибки. В случае если клиент и сервер являются частями одного процесса (локальный вызов процедуры на рис. 15.1), клиенту не нужно беспокоиться о возникновении ошибок на сервере, и наоборот. Однако если клиент и сервер находятся в различных процессах, нужно учесть возможность досрочного завершения одного из них и предусмотреть способ уведомления второго об этом событии. Об этом нужно заботиться вне зависимости от того, находятся ли клиент и сервер на одном узле или нет. Досрочное завершение сервера Если клиент блокируется в вызове door cal 1, ожидая получения результатов, ему нужно каким-то образом получить уведомление о завершении потока сервера по какой-либо причине. Посмотрим, что происходит в этом случае, прервав работу сервера вызовом pthreadexit. Это приведет к завершению потока сервера (а не всего процесса). В листинге 15.20 приведен текст процедуры сервера. Листинг 15.20. Процедура сервера, завершающая работу сразу после запуска doors/serverintrl.c 1 finclude unpipch 2 void 3 servprocCvoid *cookie, char *dataptr, size t datasize, 4 door desc t *descptr. size t ndesc) 6 long arg, result: 7 pthread exit(NULL): /* посмотрим, что произойдет с клиентом */ 8 arg = *((long *) dataptr): 9 result = arg * arg: 10 Door return((char *) &result. sizeofCresult). NULL. 0): 11 } Оставшаяся часть сервера не претерпевает изменений по сравнению с листингом 15.2, а программу-клиент мы берем из листинга 15.1. Запустив клиент, мы увидим, что вызов с1оог са11 возвращает ошибку EINTR, если процедура сервера завершается досрочно; Solaris X clientintrl /tmp/doorl 11 door call error: Interrupted system call Непрерываемость системного вызова door call Документация на cloor cal 1 предупреждает, что эта функция не предполагает возможности перезапуска (библиотечная функция с1оог са11 делает системный вызов с тем же именем). Мы можем убедиться в этом, изменив процедуру сервера таким образом, чтобы она делала паузу в 6 секунд перед возвращением, что показано в листинге 15.21. Листинг 15.21. Процедура сервера делает паузу в 6 секунд doors/serveri ntг2.с 1 finclude unpipc.h 2 void 3 servprocCvoid *cookie. char *dataptr. size t datasize, 4 door desc t *descptr, size t ndesc) 6 long arg, result: 7 sleepC6): /* клиент получает сигнал SIGCHLD */ 8 arg = *CClong *) dataptr); 9 result = arg * arg; 10 Door returnCcchar *) &result, sizeofCresult). NULL. 0): 11 } Изменим теперь клиент из листинга 15.2: установим обработчик сигнала SIGCHLD, добавив порождение процесса и завершение порожденного процесса через 2 секунды. Таким образом, через 2 секунды после вызова с1оог са11 дочерний процесс завершит работу, а родительский перехватит сигнал SIGCHLD и произойдет возврат из обработчика сигнала, прерывающий системный вызов doorcall. Текст программы-клиента показан в листинге 15.22. Листинг 15.22. Клиент, перехватывающий сигнал SIGCHLD doors/clientintr2.c 1 finclude unpipc.h 2 void 3 sig chldCint signo)
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |