Распределение клиентских соединений между дочерними процессами
Распределение клиентских соединений между дочерними процессами
Следующей темой обсуждения является распределение клиентских соединений между свободными дочерними процессами, блокированными в вызове функции accept. Для получения этой информации мы модифицируем функцию main, размещая в совместно используемой области памяти массив счетчиков, которые представляют собой длинные целые числа (один счетчик на каждый дочерний процесс). Это делается следующим образом:
long *cptr, *meter(int); /* для подсчета количества клиентов на один
дочерний процесс */
cptr = meter(nchildren); /* перед порождением дочернего процесса */
В листинге 30.10 показана функция meter.
Листинг 30.10. Функция meter, которая размещает массив в совместно используемой памяти
//server/meter.c
1 #include "unp.h"
2 #include <sys/mman.h>
3 /* Размещаем массив "nchildren" длинных целых чисел
4 * в совместно используемой области памяти.
5 * Эти числа используются как счетчики количества
* клиентов, обслуженных данным дочерним процессом,
6 * см. с. 467-470 книги [110]"
7 */
8 long*
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, имеющийся в ядре алгоритм планирования равномерно распределяет нагрузку, так что в результате все дочерние процессы обслуживают примерно одинаковое количество клиентских запросов.
Данный текст является ознакомительным фрагментом.