Строки 26-31. Подпрограмма do_thread(). В данной подпрограмме вначале выполняется отключение потока, чтобы не было необходимости присоединяться к нему с помощью функции join () из главного потока после завершения работы данного потока. Затем вызывается подпрограмма handle_connection (), и после завершения ее работы сокет закрывается.
Как и другие серверы, описанные ранее, сервер web_threadl.pl практически переводит себя в фоновый режим во время запуска. Сообщения о состоянии этого сервера записываются в системный журнал, и его можно остановить, отправив ему сигнал TERM или INT.
% kill -TERM 'cat /tmp/web_thread.pid'
Этот многопоточный сервер имеет удивительно простую конструкцию.
Простой сервер с предварительным формированием потоков
В отличие от многопоточного сервера, сервер с предварительным формированием потоков действует по принципу заблаговременного создания своих рабочих потоков. Такая схема очень выгодна при многочисленных запросах, к примеру, при частом обращении к страницам сайта, на котором можно купить квартиру или продать квартиру. В каждом рабочем потоке выполняется независимый цикл accept (). Сервер с предварительным формированием потоков, упрощенный до предела, выглядит следующим образом.
use Thread; use IO::Socket; use Web; use constant PRETHREAD => 5; my $socket = TO::Socket::INET->new( LocalPort => $port, Listen => SОМАХCONN, Reuse => 1 ) or die; Thread->new(&do_thread,$socket) for (1..PRETHREAD); sleep; sub do_thread { my $socket = shift while (1) { next unless my $c — $socket->accept handle_connection($ с) ; close $c; } }
В главном потоке создается приемный сокет, затем запускаются потоки выполнения, число которых определено константой PRETHREAD, и в каждом потоке вызывается подпрограмма do_thread (). После этого главный поток переходит в состояние ожидания. Между тем, каждый рабочий поток входит в цикл accept( ), в котором он ожидает входящие соединения, обслуживает их, а затем снова возвращается в состояние ожидания. Выбор потока для обслуживания того или иного соединения происходит случайным образом.
Безусловно, дело обстоит далеко не так просто. Этот код не будет работать на всех платформах, поскольку в некоторых системах вызов функции accept () завершается аварийно, если ее вызывают более чем в одном потоке одновременно, и поэтому нужен механизм для обеспечения того, чтобы лишь один поток в любой момент времени мог вызвать функцию accept ().