Чтение онлайн

на главную - закладки

Жанры

UNIX: разработка сетевых приложений
Шрифт:

Затем мы модифицируем нашу функцию

child_main
(см. листинг 30.9) таким образом, чтобы каждый дочерний процесс увеличивал значение соответствующего счетчика на единицу при завершении функции
accept
, а после завершения выполнения всех дочерних процессов обработчик сигнала
SIGINT
выводил бы упомянутый массив счетчиков.

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

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

Коллизии при вызове функции select

Рассматривая данный пример в 4.4BSD, мы можем исследовать еще одну проблему, которая встречается довольно редко и поэтому часто остается непонятой до конца. В разделе 16.13 [128] говорится о коллизиях( collisions), возникающих при вызове функции

select
несколькими процессами на одном и том же дескрипторе, и о том, каким образом ядро решает эту проблему. Суть проблемы в том, что в структуре
socket
предусмотрено место только для одного идентификатора процесса, который выводится из состояния ожидания по готовности дескриптора. Если же имеется несколько процессов, ожидающих, когда будет готов данный дескриптор, то ядро должно вывести из состояния ожидания все процессы, блокированные в вызове функции
select
, так как ядро не знает, какие именно процессы ожидают готовности данного дескриптора.

Коллизии при вызове функции

select
в нашем примере можно форсировать, предваряя вызов функции
accept
из листинга 30.9 вызовом функции
select
в ожидании готовности к чтению на прослушиваемом сокете. Дочерние процессы будут теперь блокированы в вызове функции
select
, а не в вызове функции accept. В листинге 30.11 показана изменяемая часть функции
child_main
, при этом измененные по отношению к листингу 30.9 строки отмечены знаками
+
.

Листинг 30.11. Модификация листинга 30.9: блокирование в вызове select вместо блокирования в вызове accept

printf("child %ld starting\n", (long)getpid);

+ FD_ZERO(&rset);

for (;;) {

+ FD_SET(listenfd, &rset);

+ Select(listenfd+1, &rset, NULL, NULL, NULL);

+ if (FD_ISSET(listenfd, &rset) == 0)

+ err_quit("listenfd readable");

+

clilen = addrlen;

connfd = Accept(listenfd, cliaddr, &clilen);

web_child(connfd); /* обработка запроса */

Close(connfd);

}

Если, проделав это изменение, мы проверим значение счетчика ядра BSD/OS

nselcoll
, мы увидим, что в первом случае при запуске сервера произошло 1814 коллизий, а во втором случае — 2045. Так как при каждом запуске сервера два клиента создают в сумме 5000 соединений, приведенные выше значения указывают, что примерно в 35-40% случаев вызовы функции
select
приводят к коллизиям.

Если сравнить значения

времени, затраченного центральным процессором в этом примере, то получится, что при добавлении вызова функции
select
это значение увеличивается с 1,8 до 2,9 с. Частично это объясняется, вероятно, добавлением системного вызова (так как теперь мы вызываем не только
accept
, но еще и
select
), а частично — накладными расходами, связанными с коллизиями.

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

accept
, а не с функцией
select
.

30.7. Сервер TCP с предварительным порождением процессов и защитой вызова accept блокировкой файла

Описанная выше реализация, позволяющая нескольким процессам вызывать функцию

accept
на одном и том же прослушиваемом дескрипторе, возможна только для систем 4.4BSD, в которых функция
accept
реализована внутри ядра. Ядра системы SVR4, в которых accept реализована как библиотечная функция, не допускают этого. В самом деле, если мы запустим сервер из предыдущего раздела, в котором имеется несколько дочерних процессов, в Solaris 2.5 (система SVR4), то вскоре после того, как клиенты начнут соединяться с сервером, вызов функции
accept
в одном из дочерних процессов вызовет ошибку
EPROTO
, что свидетельствует об ошибке протокола.

ПРИМЕЧАНИЕ

Причины возникновения этой проблемы с библиотечной версией функции accept в SVR4 связаны с реализацией потоков STREAMS и тем фактом, что библиотечная функция accept не является атомарной операцией. В Solaris 2.6 эта проблема решена, но в большинстве реализаций SVR4 она остается.

Решением этой проблемы является защита вызова функции

accept
при помощи блокировки, так что в данный момент времени только один процесс может быть блокирован в вызове этой функции. Другие процессы также будут блокированы, так как они будут стремиться установить блокировку для вызова функции
accept
.

Существует несколько способов реализации защиты вызова функции

accept
, о которых рассказывается во втором томе [2] данной серии. В этом разделе мы используем блокировку файла функцией
fcntl
согласно стандарту POSIX.

Единственным изменением в функции

main
(см. листинг 30.6) будет добавление вызова функции
my_lock_init
перед началом цикла, в котором создаются дочерние процессы:

+ my_lock_init("/tmp/lock.XXXXXX"); /* один файл для всех дочерних

2

Стивенс У. UNIX: взаимодействие процессов. — СПб.: Питер, 2002.

процессов */

for (i = 0; i < nchildren; i++)

pids[i] = child_make(i, listenfd, addrlen); /* возвращение

родительского процесса */

Поделиться:
Популярные книги

Блуждающие огни 4

Панченко Андрей Алексеевич
4. Блуждающие огни
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Блуждающие огни 4

Я сделаю это сама

Кальк Салма
1. Магический XVIII век
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Я сделаю это сама

Флеш Рояль

Тоцка Тала
Детективы:
триллеры
7.11
рейтинг книги
Флеш Рояль

Боярышня Дуняша

Меллер Юлия Викторовна
1. Боярышня
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Боярышня Дуняша

Газлайтер. Том 8

Володин Григорий
8. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 8

Леди для короля. Оборотная сторона короны

Воронцова Александра
3. Королевская охота
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Леди для короля. Оборотная сторона короны

На границе империй. Том 10. Часть 1

INDIGO
Вселенная EVE Online
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 1

Черный Маг Императора 5

Герда Александр
5. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 5

Невест так много. Дилогия

Завойчинская Милена
Невест так много
Любовные романы:
любовно-фантастические романы
7.62
рейтинг книги
Невест так много. Дилогия

Идеальный мир для Социопата 3

Сапфир Олег
3. Социопат
Фантастика:
боевая фантастика
6.17
рейтинг книги
Идеальный мир для Социопата 3

Повелитель механического легиона. Том VIII

Лисицин Евгений
8. Повелитель механического легиона
Фантастика:
технофэнтези
аниме
фэнтези
5.00
рейтинг книги
Повелитель механического легиона. Том VIII

Наследник павшего дома. Том I

Вайс Александр
1. Расколотый мир
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Наследник павшего дома. Том I

Крещение огнем

Сапковский Анджей
5. Ведьмак
Фантастика:
фэнтези
9.40
рейтинг книги
Крещение огнем

Камень Книга двенадцатая

Минин Станислав
12. Камень
Фантастика:
боевая фантастика
городское фэнтези
аниме
фэнтези
5.00
рейтинг книги
Камень Книга двенадцатая