пятница, 8 февраля 2013 г.

выполнение в потоке порта заверешения

Вызов accept возвращает нам сокет очередного клиента, в который можно писать и из которого можно читать как из обычного файла. В вашем случае тут может быть файл на диске или любой другой IO-объект.

SOCKET clientsock=WSAAccept(listensock,(sockaddr *)&clientaddr,&clientsize,0,0);

Теперь, когда потоки созданы, можно начинать принимать клиенты и их сообщения. Код инициализации Winsock я здесь приводить не буду (но он есть в тексте исходников этой статьи), поэтому просто напишу:

Обращаю ваше внимание: мы передаем рабочим потокам хендл порта завершения в качестве параметра. Он понадобится им, когда потоки будут заявлять о своей готовности поработать. Сама функция WorkingThread() будет приведена ниже.

HANDLE hWorking=CreateThread(0,0,(LPTHREAD_START_ROUTINE)&WorkingThread,iocp,0,0);

Следующим шагом является создание потоков, которые будут задействованы в пуле. Тут нельзя дать универсального совета. Некоторые говорят, что потоков должно быть в два раза больше процессоров в системе, другие, что их количество должно быть равно, третьи динамически изменяют размеры пула. Как тут поступить зависит от приложения и конфигурации компьютера. У меня старенький пенек с HyperThreading, поэтому система видит мой процессор как два. По этой причине в моем примере будет 2 рабочих потока в пуле.

создаст новый объект порта завершения и вернет нам его хендл. Здесь в качестве первого аргумента передается значение INVALID_HANDLE_VALUE, которое и означает то, что нам нужен новый порт. Следующие два аргумента должны иметь значение 0. При создании можно указать сколько потоков одновременно смогут работать для этого порта с помощью последнего аргумента. Если указать 0, то будет использовано значение, равное количеству процессоров в системе.

HANDLE iocp=CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);

Что примечательно, этот же вызов используется для связывания хендла файла с уже существующим портом. Зачем так было делать неизвестно.

DWORD NumberOfConcurrentThreads);

HANDLE ExistingCompletionPort,

HANDLE CreateIOCompletionPort(

Итак, для начала было бы неплохо этот самый порт создать. Делается это APIшкой

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

Выглядит запутанно? На практике несколько проще.

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

Объект «порт», по сути, представляет собой очередь событий ядра, из которой извлекаются и в которую добавляются сообщения об операциях ввода/вывода. Естественно туда добавляются не все текущие операции, а только те, которые мы указали порту. Делается это путем связывания дескриптора (хендла) файла (не обязательно именно файла на диске, это может быть сокет, пайп, мэилслот и т.д.) с дескриптором порта. Когда над файлом инициируется асинхронная операция ввода/вывода, то после ее завершения соответствующая запись добавляется в порт.

Привет. Сейчас я расскажу вам о механизме IO Completion Ports в Windows. Разработчики описывают порт завершения как «средство, повышающее производительность приложений, часто использующих операции ввода/вывода». В общем-то, они и не врут, поэтому IOCP часто используют при написании масштабируемых серверных приложений. Однако же считается, что порт завершения тема мудреная и тяжелая для понимания.

Порт завершения (Completion Port)

Порт завершения (Completion Port) / Хабрахабр

Комментариев нет:

Отправить комментарий