Мьютекс, блокировка файла и параллельные вызовы функции accept
Предварительное создание ведомых процессов особенно просто осуществляется в системе Linux, поскольку эта операционная система различает между собой параллельные процессы, вызывающие функцию accept с конкретным сокетом. Бще более важно то, что система Linux эффективно обрабатывает параллельные вызовы. Поэтому каждый из предварительно созданных ведомых процессов наследует дескриптор ведущего сокета, и каждый ведомый процесс вызывает функцию accept. Система оставляет все ведомые процессы в заблокированном состоянии до тех пор, пока не поступит запрос на установление соединения. В этот момент система разблокирует один и только один ведомый процесс.
К сожалению, не во всех версиях UNIX предусмотрена такая же организация работы, как в Linux. В некоторых версиях UNIX не допускается параллельный вызов функции accept: после того как один процесс вызовет функцию accept с некоторым сокетом, все последующие вызовы возвращают сообщения об ошибке. Другие версии UNIX допускают параллельные вызовы, но обрабатывают их неэффективно. В частности, при поступлении нового запроса на установление соединения эти версии операционной системы предусматривают разблокирование сразу всех процессов, в которых была вызвана функция accept. Новое соединение получает тот процесс, который был активизирован первым; после их активизации все остальные процессы обнаруживают, что отсутствует доступное соединение, и возвращаются в заблокированное состояние. Поэтому если заблокировано К процессов, то активизация Я-1 из них приводит к непроизводительным затратам ресурсов. Каждый активизированный процесс требует переключения контекста; на это расходуется процессорное время, после чего процесс обнаруживает, что запрос на установление соединения был уже принят, и возвращается в заблокированное состояние. Чехол для psp go цена 400 рублей.
Может ли метод предварительного создания использоваться в операционной системе, которая не обеспечивает эффективного параллельного выполнения функции accept? Ответ на этот вопрос является положительным. В этом случае вместо, применения параллельных вызовов функции accept, в программе необходимо использовать разделяемый мьютекс или блокировку файла (например, с применением функции flock) для обеспечения того, чтобы только один ведомый процесс одновременно вызывал функцию accept. Например, при использовании мьютекса каждый ведомый процесс вызывает функцию pthreadjnutex_lock перед вызовом функции accept, а после ее вызова — функцию pthread_mutex_unlock. В любой момент все ведомые процессы, кроме одного, блокируются в вызове функции pthread_mutex_lock, а один ведомый процесс продолжает выполняться и переходит к вызову функции accept. После возврата управления из функции accept выполняющийся ведомый процесс вызывает функцию pthreadjnutexjmlock, позволяя продолжить работу одному и только одному ведомому процессу, в результате чего в любое время функцию accept вызывает только один процесс, а системные ресурсы используются эффективно.
На практике ведущий процесс может использоваться для уничтожения процессов-зомби, если в нем выполняется цикл для повторного вызова системной функции wait3. Бели же ведущий процесс завершит свою работу, то родительским для ведомых процессов становится системный процесс init.