Алексей Ширшов
Итак, снова многопоточность. Вы скажете, какая избитая тема, уж сколько можно про это писать! Да, написано про нее немало. Практически каждый программист, который с нею сталкивался (то есть хоть раз в жизни вызвал функцию CreateThread), может заявить, что он про нее знает все или почти все. Но это глубокое заблуждение. Создание эффективных многопоточных серверов (а делать многопоточного клиента особого смысла нет) – дело сложное и требующее хороших знаний системных механизмов: многопоточности, синхронизации, асинхронного ввода/вывода и много другого. В этой статье я коснусь темы организации пула потоков для эффективной обработки клиентских запросов.
Зачем организовывать пул потоков? Вопрос очень широко распространен, и на него давно существует ответ. Для тех, кто этот ответ знает, данный раздел не будет чем-то новым, так что можете его пропускать.
При приходе клиентского запроса у сервера имеется несколько вариантов действий:
Обрабатывать все запросы в одном потоке;
Обрабатывать каждый запрос в отдельном потоке;
Организовать пул потоков.
Рассмотрим каждый из сценариев.
Обработка всех запросов в одном потоке
Сразу понятно, что это решение подходит только для очень ограниченного числа случаев, в которых количество клиентов невелико, и обращаются они к серверу не часто. Эта самая простая схема работы: минимум потоков, минимум ресурсов, и не нужно ничего синхронизировать. Главное, что нужно сделать – построить очередь входящих запросов, чтобы они не терялись при последовательной обработке. Это несложно, к тому же можно взять уже готовые решения: например, СОМ-сервер STA singleton.
Это, пожалуй, самая популярная у разработчиков схема. В ней для каждого клиентского запроса создается отдельный поток. Решение это простое и для многих случаев удовлетворительное, так как при этом нужно заботиться, по большому счету, только о синхронизации общих переменных потоков (а их может и не быть). Такая схема работает следующим образом: первичный поток приложения прослушивает клиентские запросы и при поступлении каждого создает новый поток, передавая ему клиентский пакет (данные или команду). Созданный поток выполняет соответствующую обработку, передает результаты обратно клиенту, или же помещает их в БД (или еще куда-нибудь), и завершает свое сущес