Читаем UNIX: разработка сетевых приложений полностью

13-15 В приведенных ранее примерах взаимных исключений Pthread мы инициализировали глобальные статические взаимные исключения, используя константу PTHREAD_MUTEX_INITIALIZER(см., например, листинг 26.12). Но располагая взаимное исключение в совместно используемой памяти, мы должны вызвать некоторые библиотечные функции Pthreads, чтобы сообщить библиотеке о наличии семафора в совместно используемой памяти и о том, что он будет применяться для синхронизации потоков, относящихся к различным процессам. Мы должны инициализировать структуру pthread_mutexattr_tзадаваемыми по умолчанию атрибутами взаимного исключения, а затем установить значение атрибута PTHREAD_PROCESS_SHARED. (По умолчанию значением этого атрибута должно быть PTHREAD_PROCESS_PRIVATE, что подразумевает использование взаимного исключения только в пределах одного процесса.) Затем вызов pthread_mutex_initинициализирует взаимное исключение указанными атрибутами.

В листинге 30.15 показаны только функции my_lock_waitи my_lock_release. Они содержат вызовы функций Pthreads, предназначенных для блокирования и разблокирования взаимного исключения.

Листинг 30.15. Функции my_lock_wait и my_lock_release: использование блокировок Pthread

//server/lock_pthread.c

17 void

18 my_lock_wait

19 {

20  Pthread_mutex_lock(mptr),

21 }

22 void

23 my_lock_release

24 {

25  Pthread_mutex_unlock(mptr);

26 }

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

<p>30.9. Сервер TCP с предварительным порождением процессов: передача дескриптора</p>

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

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

В данном примере для каждого дочернего процесса нам нужна некая структура, содержащая информацию о нем. Заголовочный файл child.h, в котором определяется структура Child, показан в листинге 30.16.

Листинг 30.16. Структура Child

//server/child.h

1 typedef struct {

2  pid_t child_pid;  /* ID процесса */

3  int child_pipefd; /* программный (неименованный) канал между

                        родительским и дочерним процессами */

4  int child_status; /* 0 = готово */

5  long child_count; /* количество обрабатываемых соединений */

6 } Child;

7 Child *cptr; /* массив структур Child */

Мы записываем идентификатор дочернего процесса, дескриптор программного канала (pipe) родительского процесса, связанного с дочерним, статус дочернего процесса и количество обрабатываемых дочерним процессом клиентских соединений. Это количество выводится обработчиком сигнала SIGINTи позволяет нам отслеживать распределение клиентских запросов между дочерними процессами.

Перейти на страницу:

Похожие книги

Основы программирования в Linux
Основы программирования в Linux

В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стан­дартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым. Для начинающих Linux-программистов

Нейл Мэтью , Ричард Стоунс , Татьяна Коротяева

ОС и Сети / Программирование / Книги по IT
1001 совет по обустройству компьютера
1001 совет по обустройству компьютера

В книге собраны и обобщены советы по решению различных проблем, которые рано или поздно возникают при эксплуатации как экономичных нетбуков, так и современных настольных моделей. Все приведенные рецепты опробованы на практике и разбиты по темам: аппаратные средства персональных компьютеров, компьютерные сети и подключение к Интернету, установка, настройка и ремонт ОС Windows, работа в Интернете, защита от вирусов. Рассмотрены не только готовые решения внезапно возникающих проблем, но и ответы на многие вопросы, которые возникают еще до покупки компьютера. Приведен необходимый минимум технических сведений, позволяющий принять осознанное решение.Компакт-диск прилагается только к печатному изданию книги.

Юрий Всеволодович Ревич

Программирование, программы, базы данных / Интернет / Компьютерное «железо» / ОС и Сети / Программное обеспечение / Книги по IT