Вверх ↑
Этот топик читают: Гость
Ответов: 655
Рейтинг: 18
#196: 2017-03-07 19:29:21 ЛС | профиль | цитата
Netspirit, спасибо!
Netspirit писал(а):
AutoReceive=False, чтобы зря каждый раз не создавало поток чтения данных

А когда запустится поток чтения данных?
карма: 0

0
Ответов: 4628
Рейтинг: 749
#197: 2017-03-08 11:56:52 ЛС | профиль | цитата
При AutoReceive=True запускается сразу после успешного подключения. Иначе вручную нужно вызвать doStartReceiving.

Редактировалось 2 раз(а), последний 2017-03-08 11:58:13
карма: 26

0
Ответов: 655
Рейтинг: 18
#198: 2017-03-08 23:04:29 ЛС | профиль | цитата
Netspirit, спасибо!
карма: 0

0
Ответов: 817
Рейтинг: 52
#199: 2017-03-28 21:35:13 ЛС | профиль | цитата
nesco писал(а):

-= DriveR =- писал(а):
Думаю не стОит сомневаться, надо добавлять

Решение Автора -- закон

Netspirit писал(а):
Давай пока пусть месяца два полежат. Пусть народ попробует их в реальных приложениях.


Времени прошло значительно больше чем пара месяцев, еще не принято решение о добавлении этих компонентов в стандартную палитру?
карма: 1

0
Разработчик
Ответов: 26113
Рейтинг: 2126
#200: 2017-03-29 01:40:46 ЛС | профиль | цитата
-= DriveR =- писал(а):
Времени прошло значительно больше чем пара месяцев, еще не принято решение о добавлении этих компонентов в стандартную палитру?

Там автор все еще что-то шерстит.
карма: 22

0
Ответов: 4628
Рейтинг: 749
#201: 2017-03-29 10:46:34 ЛС | профиль | цитата
Ну, уже вроде как бы всё устаканилось. Но, конечно, ещё будут доработки.
карма: 26

0
Ответов: 578
Рейтинг: 14
#202: 2017-04-14 08:08:41 ЛС | профиль | цитата
Этот компонент только со String работает, Stream нельзя?
карма: 0

0
Ответов: 4628
Рейтинг: 749
#203: 2017-04-18 11:52:16 ЛС | профиль | цитата
Нет. Реализация собственных протоколов для отправки произвольных данных - /topic/65137
карма: 26

0
Ответов: 655
Рейтинг: 18
#204: 2017-04-20 14:59:00 ЛС | профиль | цитата
Netspirit, Если не затруднит объясни пожалуйста про потоки внутри сервера и клиента.
Собственно мне требуется на клиенте проверять наличие новых данных в БД, затем паковать их и отправлять на сервер.
Одно из условий - пока сервер обрабатывает полученный пакет от клиента, клиент не должен слать последующие пакеты.
Когда сервер обработает пакет он отключит клиента, собственно после отключения можно будет повторно подключиться и отправить следующие данные.
Такая схема с отключением\подключением сделана ввиду того что данные шлются в HTTP POST запросах, ну и потому что появляются они не часто и удерживать соединение не имеет смысла.

Вопрос по потокам следующий:
Какие события происходят в одном потоке а какие в разных?
onConnect\onDisconnect это события одного потока?
onReceive - другого?
Правильно ли в моей схеме используется критическая секция?

Add(MainForm,2953706,21,105)
{
}
Add(TCPClient,12524208,147,98)
{
Port=8080
Point(onErrorConnect)
Point(onErrorSend)
link(onConnect,1207998:doWork1,[])
link(onDisconnect,10157546:doWork2,[])
link(onErrorConnect,5078233:doWork2,[])
link(onErrorSend,5078233:doWork3,[(200,139)])
}
Add(ChanelToIndex,1207998,217,112)
{
link(onIndex,2449697:doValue,[])
}
Add(SafeMode,11531109,315,112)
{
Name="con"
link(onSafeMode,15323504:doData,[])
}
Add(If_else,12946932,413,187)
{
Op2=Integer(1)
link(onTrue,7776816:In,[])
link(Op1,11721838:Var,[])
}
Add(GlobalVar,11721838,413,112)
{
Name="con_state"
Data=Integer(1)
}
Add(HubEx,10157546,196,119)
{
link(onEvent,1207998:doWork2,[])
}
Add(HubEx,5078233,196,126)
{
Angle=3
link(onEvent,10157546:doWork3,[])
}
Add(Thread,14368023,314,187)
{
link(onExec,102960:doSafeMode,[])
}
Add(LineBreak,7517986,644,187)
{
Caption="что_то_дальше_выполняется"
Primary=[7776816,-175,0]
}
Add(SafeMode,102960,364,187)
{
Name="con"
WaitMode=1
link(onSafeMode,12946932:doCompare,[])
}
Add(Memory,2449697,266,112)
{
link(onData,11531109:doSafeMode,[])
}
Add(DoData,15323504,364,112)
{
link(onEventData,11721838:doValue,[])
link(Data,2449697:Value,[(370,100)(255,100)(255,156)(272,156)])
}

карма: 0

0
Ответов: 4628
Рейтинг: 749
#205: 2017-04-20 16:07:09 ЛС | профиль | цитата
Gunnman писал(а):
Какие события происходят в одном потоке а какие в разных?

События onConnect/onErrorConnect происходят либо в потоке, вызвавшем doConnect (при AsyncConnect=False), либо в параллельном потоке (при AsyncConnect=True)

События onSend/onErrorSend происходят либо в потоке, вызвавшем doSend, либо в параллельном потоке после doSendAsync

Событие onReceive происходит в параллельном потоке чтения данных, onClientConnect - в параллельном потоке приёма подключений.

Событие onDisconnect/onClientDisconnect происходит либо в потоке, вызвавшем doDisconnect, либо в параллельном потоке чтения данных.

Поскольку прием данных и асинхронную отправку обслуживают по несколько параллельных потоков, то источником одного события в разное время могут быть разные потоки. Но, так как точка события одна, то нужно считать, что оно просто происходит в параллельном потоке (а каком именно - для автора схемы не имеет значения).

Если свойство AsyncEvents=False, то все перечисленные события, происходящие в параллельных потоках, вызываются из главного потока приложения (очереди сообщений). Для невизуальных приложений (не имеющих очереди сообщений), AsyncEvents всегда True.

Gunnman писал(а):
Правильно ли в моей схеме используется критическая секция?
Вроде правильно, только AsyncEvents наверное должно быть True. Аккуратно следует использовать критическую секцию на событиях из главного потока (например, события от оконных элементов). Возможна такая ситуация, когда параллельный поток заходит в секцию, затем вызывает метод какого-то визуального компонента, в результате которого генерируется оконное сообщение и метод должен дождаться обработки этого сообщения. Тогда, если на это сообщение есть событие, использующее ту же критическую секцию, произойдёт deadlock: праллельный поток ждёт обработки сообщения, а главный поток не может завершить его обработку, так как ждёт освобождения критической секции параллельным потоком.

Редактировалось 4 раз(а), последний 2017-04-20 16:20:05
карма: 26

0
Ответов: 655
Рейтинг: 18
#206: 2017-04-20 22:05:31 ЛС | профиль | цитата
Для невизуальных приложений (не имеющих очереди сообщений), AsyncEvents всегда True.


Как быть с сетевыми контроллерами которые на каждую принятую команду отвечают что-либо?
У меня происходит следующее - есть массив команд которые нужно послать по очереди (шлю через перебором через ArrayEnum), если AsyncEvents=False то контроллер отрабатывает все команды и на каждую отвечает, если AsyncEvents=True то ответы получаю не на все отправленные команды..

--- Добавлено в 2017-04-20 22:21:52

И еще вопросы:

1) Есть поток с задержкой 1000ms, он вызывает подключение к серверу и отправку данных.
Например данных оказалось больше или скорость канала просела и за 1000ms мы не успеваем отправить, что в этом случае происходит с потоком по истечению 1000ms?
2) Нужно ли использовать асинхронные события? Можно какой-нибудь пример ситуации для чайников))



Редактировалось 3 раз(а), последний 2017-04-20 22:22:14
карма: 0

0
Ответов: 4628
Рейтинг: 749
#207: 2017-04-21 12:28:42 ЛС | профиль | цитата
Gunnman писал(а):
если AsyncEvents=True то ответы получаю не на все отправленные команды
Если данные отправляются из главного потока (например, по командах обычного таймера), то при AsyncEvents=False событие onReceive не произойдёт, пока не отработает событие таймера (в твоем случае когда весь список команд будет перебран). После отработки поток приёма данных получает возможность вызвать все необходимые события onReceive.
При AsyncEvents=True (или при переборе команд с вызовом doSend не из главного потока) событие onReceive может произойти в процессе перебора - ты шлешь очередную команду очередному клиенту и в это самое время может произойти событие onReceive как ответ от предыдущего клиента.

Мне кажется, тут нужно менять логику в схеме для реализации "запрос-ответ". Это не принципиально зависит от AsyncEvents - в любом случае тебе нужно дождаться прихода ответа, причем, в правильном порядке.
Сделать это можно так. Специальный паралельный поток сбрасывает событие (компонент Events) затем шлет одну команду и останавливается на ожидание срабатывания события (компонент WaitObject). Событие onReceive выполняет необходимую обработку ответа, а затем сигналит то же событие Events, позволяя отправляющему потоку продолжить исполнение и отправить следующую команду.

Gunnman писал(а):
что в этом случае происходит с потоком по истечению 1000ms?
Если под "потоком" имеется в виду компонент Thread, то в этом случае ничего не происходит - поток остановится, пока данные не будут отправлены. Если данные не были приняты клиентом на протяжении SendTimeout, сработает событие onErrorSend.
Но тут есть одна проблемка: у сокета есть свой буфер. И если при отправке в буфере есть свободное место, то новые данные будут записаны в буфер, метод doSend/doSendAsync отработает сразу, событие onSend будет получено. При этом, не факт что клиент эти данные получит: если после этого глюкнет сеть или клиент отключится, то мы получим событие onDisconnect (поток приема данных обнаружит ошибку чтения сокета, хотя, возможно, и не всегда), но мы не сможем узнать сколько реально клиент смог принять данных из буфера перед обрывом. Отправка следующих данных выдаст onErrorSend.
Если в буфере при отправке нет свободного места, отправляющий поток приостановится до освобождения буфера.

Редактировалось 2 раз(а), последний 2017-05-25 11:27:00
карма: 26

1
Голосовали:Gunnman
Ответов: 655
Рейтинг: 18
#208: 2017-04-21 15:20:42 ЛС | профиль | цитата
Если данные отправляются из главного потока (например, по командах обычного таймера)

при переборе команд с вызовом doSend не из главного потока

Запутался...

Правильно я понимаю что главный поток - это поток который создается системой при запуске ПО, далее из него мы можем вызывать уже дочерние потоки?
В таймерах и компоненте Thread есть задержка между итерациями, а как устроен главный поток? Грубо говоря запустили мы программу...главный поток вызвал какую-то функцию, цепочка событий началась. У него так же есть задержка?
п.с. спасибо за терпение, вы очень интересно объясняете))
карма: 0

0
Ответов: 4628
Рейтинг: 749
#209: 2017-04-21 16:18:00 ЛС | профиль | цитата
Gunnman писал(а):
Запутался...
Если вызвать doSend из запущенного тобой параллельного потока, то главный поток в процессе doSend будет не занят и сможет выдавать событие onReceive одновременно с твоим doSend. Это и имелось в виду.

Gunnman писал(а):
Правильно я понимаю что главный поток - это поток который создается системой при запуске ПО
Да. При запуске приложения система создаёт один поток, и в нём выполняет код, расположенный по адресу, указанному в специальном месте исполняемого файла (называется "точка входа"). После отработки кода в этом месте приложение завершает работу (даже если запустило другие потоки - они принудительно останавливаются). Для того, чтобы приложение постоянно оставалось запущеным и выполняло команды пользователя, в главном потоке оно должно запустить цикл, ожидающий какого-либо условия для завершения своей работы, ну и команд от пользователя.
GUI ("оконное") приложение реализует в этом цикле с помощью функций Windows выборку оконных сообщений, передачу их на обработку созданным в этом приложении окнам. Обычно, этот цикл завершается, когда будет закрыто первое созданое приложением окно (а точнее, в очередь сообщений будет послано сообщение WM_QUIT). Если посмотреть исходный код проектов Delphi, то можно увидеть, что сначала создается главное окно, а затем вызывается процедура Application.Run(), содержащая такой цикл. А пользователь уже управляет приложением, используя элементы управления в главном и других окнах. Всё, что он нажимает в окнах, попадает в виде сообщения в главный цикл, тот передаёт его оконной процедуре окна, в котором оно произошло, а она ищет обработчик, назначенный программистом для данного сообщения (например, в панели событий Delphi IDE).

Gunnman писал(а):
У него так же есть задержка?
Если функция выборки очередного сообщения показывает, что сообщений нет, цикл вызывает специальную функцию, которая ждёт появления сообщения. То-есть, главный поток в этот момент ничего не делает. Когда появляется сообщение, поток возобновляет свою работу и идёт на следующую итерацию цикла обработки сообщений.

Gunnman писал(а):
В таймерах и компоненте Thread есть задержка между итерациями
Да, только их природа разная - в Thread это тупо цикл и функция Sleep(), а в Таймере, возможно, то же самое, только где-то в недрах системы, и каждая итерация сопровождается посылкой в наш главный цикл сообщения таймера. MMTimer отличается от простого Timer тем, что не шлёт оконных сообщений, а прямо вызывает нужное событие "в параллельном потоке". И этим он полностью по функционалу аналогичен нашему Thread с задержкой.

Редактировалось 2 раз(а), последний 2017-05-25 11:31:56
карма: 26

0
Ответов: 655
Рейтинг: 18
#210: 2017-04-21 16:28:48 ЛС | профиль | цитата
Netspirit писал(а):
Сделать это можно так. Специальный паралельный поток шлет одну команду затем сбрасывает событие (компонент Events) и останавливается на ожидание его срабатывания (компонент WaitObject). Событие onReceive выполняет необходимую обработку ответа, а затем сигналит то же событие Events, позволяя отправляющему потоку продолжить исполнение и отправить следующую команду.



Add(MainForm,2953706,21,105)
{
Width=227
Height=146
link(onCreate,9501545:doEvent1,[])
}
Add(TCPClient,14910645,399,189)
{
IP="127.0.0.1"
Port=8080
AsyncEvents=1
link(onReceive,2593203:In,[])
link(Data,14996723:Count,[(405,177)(489,177)(489,230)(349,230)])
}
Add(Thread,13878513,105,336)
{
link(onExec,14008871:doCompare,[])
}
Add(Events,13595715,301,287)
{
}
Add(WaitObject,1611665,301,350)
{
link(onWait,9346844:doOn,[(347,356)(347,392)(149,392)(149,300)])
link(ObjHandle,13595715:ObjHandle,[])
}
Add(TCPServer,3451293,336,112)
{
Port=8080
AsyncEvents=1
link(onReceive,9299417:doEvent1,[])
link(ClientID,3451293:CurClientID,[(349,100)(378,100)(378,152)(349,152)])
}
Add(Hub,9501545,70,119)
{
OutCount=5
link(onEvent1,3451293:doStartServer,[])
link(onEvent2,14910645:doConnect,[(249,132)(249,209)])
link(onEvent3,13595715:doCreate,[(243,139)(243,293)])
link(onEvent4,9346844:doSwitch,[(103,146)(103,286)])
link(onEvent5,13878513:doStart,[(94,153)(94,342)])
}
Add(If_else,14008871,161,336)
{
Op2=Integer(1)
link(onTrue,16332363:doEvent1,[])
link(Op1,9346844:State,[])
}
Add(Hub,16332363,210,336)
{
OutCount=4
link(onEvent1,9346844:doReset,[(235,342)(235,275)(149,275)(149,293)])
link(onEvent2,13595715:doSet,[(246,349)(246,300)])
link(onEvent3,1611665:doWait,[])
link(onEvent4,13466587:In,[])
}
Add(LineBreak,3300379,252,301)
{
Caption="rst"
link(Out,13595715:doReset,[])
Primary=[2593203,203,-112]
}
Add(Switch,9346844,161,280)
{
DataOn=Integer(1)
DataOff=Integer(0)
Point(doOn)
Point(State)
}
Add(LineBreak,3708233,287,189)
{
Caption="send"
link(Out,14996723:doNext,[])
Primary=[13466587,-42,168]
}
Add(CounterEx,14996723,343,189)
{
Max=1000
link(onNext,14910645:doSend,[])
}
Add(Hub,9299417,385,112)
{
link(onEvent1,9086780:doText,[])
link(onEvent2,3451293:doSend,[(418,125)(418,85)(324,85)(324,118)])
}
Add(Label,9086780,427,112)
{
Left=35
Top=20
}

Типа такого?
п.с. а Events можно использовать с паралельным потоком?
карма: 0

0
Сообщение
...
Прикрепленные файлы
(файлы не залиты)