Распределение клиентских соединений между дочерними процессами

Распределение клиентских соединений между дочерними процессами

Следующей темой обсуждения является распределение клиентских соединений между свободными дочерними процессами, блокированными в вызове функции 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, имеющийся в ядре алгоритм планирования равномерно распределяет нагрузку, так что в результате все дочерние процессы обслуживают примерно одинаковое количество клиентских запросов.

Данный текст является ознакомительным фрагментом.