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

We use cookies. Read the Privacy and Cookie Policy

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

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

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