Плохо это по следующим причинам:
— тяжело читать
— тяжело менять логику (не гибко)
Вы описали подход к решению конкретной задачи выложив «деревянную» реализацию.
В вашей статье ценны следующие моменты:
— узкие места
— способы обработки
А они в свою очередь теряются в большом количестве плохого кода.
(например, по коду у вас разбросаны флаги, которые определяют состояние, например fStateLock. И понять логику работы коды без комментариев автора очень тяжело. И ещё тяжелее поверить в работоспособность данного решения. Так что, по сути я говорю о том, что ваш код очень тяжело сопровождать и развивать)
А на мой взгляд, в таком виде легче менять логику всего что касается низкоуровнего программирования, winapi в частности. В приведённых листингах, по большому счёту, вообще альтернативы нет. Что насчёт флагов, так то и не флаги вовсе, а поля(сокращения от английской нотации, так в Delphi почти повсеместно), не зря готовый исходник прикреплен к началу. Посмотреть на рабочий итог в нём и можно.
Отложите свой код куда-нить в чулан и через полгода попробуйте внести новую фичу поставив рядом кого-нибудь из друзей, который будет WTFcount инкрементировать. Будет интересно узнать значение этого счетчика в конечном итоге.
Я всё понимаю. Но опять таки. Исходник выложен только с той целью, что если какому-то хардкорщику из ряда системных программистов придётся столкнутся с асинхронной очередью в сокетах для него это будет подарок. Даже так как он есть. Этот топ нацелен на достаточно узкую, интересную и сложную тему, а не на пропаганду чистописания. А WTFcount чуть более чем 9000 сомнения не вызывает =)
Так и не нашел описания методов _AddRef и _Release. Если это — стандартные методы IUnknown, то автор вообще в курсе, почему они начинаются с подчеркивания?
Подчеркивание как бы намекает, что программист не должен вызывать эти методы самостоятельно, если используемый им язык правильно поддерживает COM-интерфейсы. А Object Pascal их поддерживает, вызывая _AddRef при каждом появлении интерфейсной ссылки на объект, и _Release при ее исчезновении.
Так что лучше пересмотрите использование _AddRef и _Release в коде.
Я использую интерфейсы не для реализации COM объектов, а для того чтобы не создавать ручками класс где ведётся учёт ссылок, это опять таки нужно чтобы следить за памятью в событийно ориентированном программировании. С внутренней организацией интерфейсов в Delphi я знаком более чем.
PS Собрал я вместе все куски кода, а он все равно не компилируется… Чего же не хватает?
А если серьезно, то почему мы должны догадываться, что ты там используешь? Где описание переменных, в конце концов-то?! особенно меня интересует тип переменной ProtoArray.
У меня была схожая задача. Ушло все в мультиплексирование, а событийное всякое выделил на уровень выше, уже после того как информация с сокета прочитана.
Сейчас постараюсь понять ваше решение, видно что-то понимаете, но Project3 Unit9 уже отпугивает…
Боюсь, что меня не хватит читать его. Ради всего святого, ну зачем вам COM? Он там все загадил… Ну и читать было бы легче если бы комментарии были хоть какие-то. И или я чего-то не понял, или там не waitformultiplyevent должен быть а waitforsingleobject… там-же только 1 ивент?
Быть может там где это внедрено — так лучше, но как отдельный проект выглядит оно не очень, ИМХО.
P. S. Впрочем, рад приветствовать умных людей на хабре, сил моих не хватает читать про хостинг и хабраэффект.
CoInitialize — очень хитро. Я прочитал статью и так и не понял сути, где оно все мультиплексируется, где обрабатывается. Прочитать исходники не осилил. Реквестирую картинки, как для школьников 5ого класса с гуманитарным уклоном).
P. S. если используете хитроту — комментируйте ее обязательно.
CoInitialize вызвана при старте потоков чтобы обработчики событий которые вызовет класс могли использовать COM внутри себя… Интерфейсы в дельфи ничем на прямую с COM не связаны… По этому я их использовал для учёта того используется объект где-то в других потоках или нет.
Честно сказать не расчитывал, что его будет много желающих прочесть… Просто реализаций таких сокетов на просторах очень мало, и я подумал что неплохо будет добавить.
Такс… Суть в том что обычные сокеты при большом пуле открытых соединений (актуально для не UDP протоколов) начинают тратить время на переключение контекстов потоков их обрабатывающих. Поняв это в Microsoft сделали IOCP, использование которой в дельфи я и продемонстрировал. IOCP это очередь сообщений на уровне ядра построенная специальным образом, так чтобы с помощью ограниченного кол-ва потоков обработать неограниченное кол-во запросов IO для любых конечных точек (сокеты файлы и т.д.).
Я так понимаю, этот код — часть какой-то ИС, которая наверное еще и где-то в гос. секторе работает?
Вероятно которая еще лет 10 разрабатывалась, и будет еще столько же… И тот кто будет после вас писать этот код умрет от радости)).
Я это к тому, что название функций, используемые методы очень сильно вводят в заблуждение.
Ну вот как я могу понять что кома тут и нет, что Event — один Event, а не еще какая-то хитрота 80 lvl-а?
P. S. все мы мастера ругать чужой код, и это полезно, не принимайте близко к сердцу.
Да я и не принимаю то =) Это часть стрим-сервера чат+видео+аудио. Сервер высоко нагруженный. Решил выложить, т.к. IOCP на дельфи оказалось в новьё. И никто ни слухом ни духом как его там прикручивать. По крайней мере из широкого круга программистов.
Если используется ThreadPool то для чего были созданы целых три отдельных нитки для обработки событий?
Насколько я понимаю, события можно обрабатывать при помощи RegisterWaitForSingleObject.
Да RegisterWaitForSingleObject тут бы подошла отлично если бы поддерживала сокеты. В целом идея отличная, сегодня её проверю. Спасибо! Насчёт пула — я не нашёл подходящего в стандартной библиотеке, к сожалению…
2 — Я видел такой альтернативный вариант реализации. Тоже попробую. Там интересно посмотреть как будет обстоять дело с постановкой в очередь своих собственных сообщений и с выборкой их оттуда.
В методе TIOCPSocketProto.Read:
при формировании исключения sErrorRead_WSARecv сбрасывается блокировка, а при исключении sErrorRead_GetMem — остается в заблокированном состоянии.
Windows Sockets, IOCP и Delphi