Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

Стивенс Уильям Ричард

Шрифт:

9 meter(int nchildren)

10 {

11 int fd;

12 long *ptr;

13 #ifdef MAP_ANON

14 ptr = Mmap(0, nchildren * sizeof(long), PROT_READ | PROT_WRITE,

15 MAP_ANON | MAP_SHARED, -1, 0);

16 #else

17 fd = Open("/dev/zero", O_RDWR, 0);

18 ptr = Mmap(0, nchildren * sizeof(long), PROT_READ | PROT_WRITE,

19 MAP_SHARED, fd, 0);

20 Close(fd);

21 #endif

22 return (ptr);

23 }

Мы используем неименованное отображение в память, если оно поддерживается (например, в 4.4BSD), или отображение файла

/dev/zero
(например, SVR4). Поскольку массив создается функцией
mmap
до того, как родительский процесс порождает дочерние, этот массив затем используется совместно родительским и всеми дочерними процессами, созданными функцией
fork
.

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

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
.

  • Читать дальше
  • 1
  • ...
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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