![]() |
Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply |
![]() ![]() ![]() |
|
yogin |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 88 Регистрация: 23.12.2007 Репутация: нет Всего: нет |
Приветствую!
Имеется такое взаимодействие потоков: MainVCLThread ---(создаёт экземпляр класса)--> TSomeClass --(создаёт экзепляр класса-потока)--> TSomeThread. В классе TSomeClass есть событие OnData(); такое же событие есть и в TSomeThread. Поток обрабатывает клиентский сокет, дак вот когда поток считывает с сокета очередные данные, он должен дать их главному потоку VCL, для этого я и сделал собятия OnData - по ним как по цепочке данные передаются в главный поток. (кстати, попутный вопрос: можно ли оптимальнее сделать эту "передачу по цепочке", т.к. эта цепочка может состоять не только из 2 классов, а больше, тогда можно запариться дублировать события в каждом классе только потому, что самому вложенному надо что-то передать самому верхнему классу, или такая архитектура нормальная?) Сейчас я в потоке вызываю synchronize(DoEvent) и всё работает. Но вопрос в том, как этот вызов синхронайза заменить на что-нибудь, чтобы классы по обработке данных с сокета можно ыбло переносить и использовать как в VCL приложениях, так и в консольных? Я склоняюсь к тому, что надо заменить это критическими секциями(если это не так - критСекции не подходят, то внимательно слушаю вариант), но куда прописать критСекции, где прописать входы и т.п. вот в этом хочу разобраться. |
|||
|
||||
kami |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1806 Регистрация: 25.8.2007 Где: Санкт-Петербург Репутация: 15 Всего: 72 |
А какая разница, консольное - не консольное? Окна-то все равно создавать можно. Только если консольное, нужно самому организовывать цикл выборки сообщений в главном потоке. Ну а для дополнительных - это по необходимости. Syncronize - нормальный выход. По крайней мере, если не нужно передавать доп.параметры. Он гарантирует, что метод вызовется в главном потоке (или в последних версиях - в контексте родительского потока? Но в данном случае это не важно). Критические секции - тоже выход. Но не нужно забывать, что в этом случае вызываемый метод будет работать в контексте своего потока. А для VCL это крайне нежелательно и чревато глюками. У меня похожая ситуация, тоже с сокетами. Сделано так: доп.поток при получении информации из сокета шлет PostMessage в окно родительского экземпляра класса (Post - чтобы не прерываться, но если нужно "принял и сразу обработал" - тогда SendMessage). Родительский класс в оконной процедуре считывает у потока данные. При этом методы типа GetDataFromThreadBuf (которым родитель счиывает данные из потока) и AddReceivedDataToThreadBuf (которым сам поток добавляет данные из сокета) внутри обрамлены критической секцией. Она одна и создается потоком. Таким образом, класс-родитель работает в своем потоке, ничего не знает и знать не хочет о синхронизации, всем этим рулит поток. Все довольны, все смеются. По поводу транзитных событий - может, это и некрасиво, зато (имхо) правильно - для класса все внутренности других классов должны быть черным ящиком, в который лезть не нужно. Добавлено через 2 минуты и 31 секунду Кстати, при использовании вместо Synchronize - Post(Send)Message можно передавать параметры, что может быть немаловажно... |
|||
|
||||
yogin |
|
||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 88 Регистрация: 23.12.2007 Репутация: нет Всего: нет |
в консольном приложении этот же код встанет(зависнит) на вызове synchronize, т.к. VCL-ом и не пахнет. Вот именно что мне этого и не нужно в некоторых случаях, например при разработке консольного сетевого клиента или когда принимающий сетевой код находится в DLL. В последнем случае даже если DLL подгружается VCL приложением, то синхронайз в длл зависает. Такую проблему я решил как бы не синхронно - просто выызваю событие, которое идёт потом в приложение. Вот меня именно этот фактор-то и волнует... Нормальная архитектура, у меня тоже до синхронайза была такая. Просто в новом варианте я стремился сделать всё только на CS, чтобы не делать две версии сетевого клиента(для VCL и не для VCL), но по всей видимости без этого никак... Т.к. консоле постмессагу тоже не отправить. А если выбирать между synchronize и мессагами, то архитектура мессаг мне больше симпатизирует. Я думаю можно поискать как "красиво" посылать синхронные команды консольному процессу. Полностью солидарен, ну т.е. меня не отпугивает вся эта цепь передач, я просто так поставил вопрос. А вопросом таким задался т.к. пришёл к такой концепции опытом, поэтому как бы задался вопросом "может быть есть что-то оптимальнее, до чего я пока недопёр?...".
Параметры можно брать в любом случае. Например в случае синхронайза удобнее передавать параметры, т.к. это выглядит так:
|
||||
|
|||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 16 Всего: 459 |
Есть еще такое решение, в OnIdle главного потока делать ожидание на MsgWaitForMultipleObjects . Соответственно события от сокетов обрабатывать в главном потоке не вешая его. Вообще, использование второго потока оправданно, когда требуется ждать чего-то или же нагрузка на проц столь велика, что ее неплохо бы распределить на разные ядра. Если же у нас своя очередь обработки сообщений, так даже OnIdle не нужен, а вместо GetMessage использовать MsgWaitForMultipleObjects, соответственно все операции делать в одном главном потоке асинхронно. Очень удобно. Для асинхронных операций использование потоков часто нецелесообразно.
-------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
yogin |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 88 Регистрация: 23.12.2007 Репутация: нет Всего: нет |
Я сделал для клиентского сокета отдельную нить потому что вызов метода TimerProcess() приходилось тянуть из главной нити по цепочке классов-менеджеров сокета, которые "стоят" до класса непосредственного чтения буфера сокета. Хотя их всего два... А т.е. в этом небыло острой необходимости или, можно сказать, мотивация - удобство. Или например, если сетевой код в DLL, то надо было бы создавать експортируемый метод dllTimerProcess() и обязывать, например стороннего, разработчика его вызывать, а иначе с сокета ничего не аукнится... Ещё вероятно я просто напросто имею чрезмерный идеалистический взор на архитектуру... |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 16 Всего: 459 |
При асинхронной работе количество сокетов не имеет значения. Сетевая карта, то одна и скорее всего аппаратно может работать только последовательно, так что в отсутствии ожидания отдельный поток никак не улучшает работу. Я также пользовался отдельным потоком для сокетов, в плагинах, но там я все задачи закрывал в этом потоке. Просто для универсальности. Если один плагин косячит, чтобы не вешал единственный рабочий поток.
-------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
Чучмек |
|
||||
НЭТ БИЛЭТ ![]() ![]() Профиль Группа: Участник Сообщений: 841 Регистрация: 11.5.2008 Где: СССР Репутация: 7 Всего: 41 |
А почемубы не реализовать свой Synchronize
-------------------- умную мысль держи при себе, а дурной - поделись с другими |
||||
|
|||||
![]() ![]() ![]() |
Правила форума "Delphi: WinAPI и системное программирование" | |
|
Запрещено: 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |