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

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

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)



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