Вверх ↑
Этот топик читают: Гость
Разработчик
Ответов: 25459
Рейтинг: 2070
#61: 2019-01-11 15:03:37 ЛС | профиль | цитата
Netspirit писал(а):
А у нас есть ещё компонент MutexThread - я не знаю как им пользоваться...

Это было сделано еще до SafeMode и только с Mutex-ом. Но он может производить какие-то параллельные действия, пока основные недоступны. Это была попытка нагрузить поток в момент простоя. Пример же вроде был. Вот SafeMode тоже не помешало бы событие при простое, но в режиме Wait это вряд ли получится. А может и не нужно, это так -- мысли вслух.
Netspirit писал(а):
Я правил, показывал. Но так и не приняли

Оформи его с расширением Ex, добавим

Редактировалось 3 раз(а), последний 2019-01-11 15:10:06
карма: 19

0
Ответов: 3910
Рейтинг: 620
#62: 2019-01-11 15:56:45 ЛС | профиль | цитата
nesco писал(а):
Оформи его с расширением Ex, добавим
Не надо никаких "Ex" - при открытии старых схем просто отвалятся старые связи на компонент. Функционал компонента никак не изменился. PS: убрать строчку "_event_onCreate: THI_Event;" в коде - упустил.

Вот базовая заготовка динамических потоков, как я это понял. Есть минимальная защита, но вероятно, все равно могут быть разные проблемы при более интенсивной работе потоков.

Add(InfoTip,11282530,560,721)
{
Info=#151:Ошибка "Self Destruction" - получаем сигнал и пытаемся очистить, когда событие контейнера ещё не отработало. Нужно Sleep (DeferredEvent слабо поможет) |
Width=197
Height=123
}
Add(MainForm,2953706,24,105)
{
Width=306
Height=264
Caption="Dynamic multithread"
Position=1
link(onCreate,15188141:doEvent1,[])
}
Add(Label,5227359,14,175)
{
Left=5
Top=10
Width=66
Height=17
Caption="Количество:"
}
Add(Edit,2248716,238,98)
{
Left=70
Top=5
Text="10"
}
Add(Button,12182706,77,301)
{
Left=125
Top=5
Width=95
Caption="Запустить"
link(onClick,7554984:doStart,[])
}
Add(Memo,2950724,623,112)
{
Left=5
Top=40
Width=280
Height=185
ScrollBars=2
}
Add(MultiElementEx,490853,763,301)
{
Mode=1
link(onFinish,10736544:doEvent1,[])
}
BEGIN_SDK
Add(EditMultiEx,9576897,21,21)
{
WorkCount=#5:##add|8:##select|7:##clear|7:doStart|
EventCount=#8:onThread|8:onFinish|
VarCount=#12:##eventIndex|
Width=566
Height=375
Point(##add)
Point(##select)
Point(##clear)
Point(##eventIndex)
link(doStart,11741187:doEvent1,[])
}
Add(Thread,1264527,105,119)
{
Delay=100
link(onExec,3660277:doNext,[])
}
Add(Hub,11741187,56,42)
{
link(onEvent1,4473815:doRandom,[])
link(onEvent2,1264527:doStart,[(88,55)(88,125)])
}
Add(Random,4473815,112,42)
{
Min=5
Max=30
link(onRandom,3660277:doMax,[(216,48)(216,132)])
}
Add(CounterEx,3660277,252,119)
{
Min=1
Default=1
Point(doMax)
Point(onThroughMax)
link(onNext,14584811:doSafeMode,[(362,125)(362,27)])
link(onThroughMax,16713849:doEvent1,[])
}
Add(Hub,16713849,329,126)
{
link(onEvent1,14740393:doSafeMode,[])
link(onEvent2,1264527:doStopFlag,[(368,139)(368,169)(93,169)(93,132)])
}
Add(SafeMode,14740393,441,126)
{
Name="Conatiner"
link(onSafeMode,9576897:onFinish,[(528,132)(528,34)])
AddHint(-11,36,60,13,Name)
}
Add(SafeMode,14584811,441,21)
{
Name="Conatiner"
link(onSafeMode,9576897:onThread,[])
AddHint(-11,36,60,13,Name)
}
Add(InfoTip,4383503,392,203)
{
Info=#69:Критическая секция на выходы контейнера - для защиты внутреннего кода|
Width=162
Height=67
}
END_SDK
Add(LineBreakEx,12595872,420,266)
{
Caption="count"
Type=2
}
Add(LineBreakEx,13591516,238,140)
{
Caption="count"
Type=3
link(_Data,2248716:Text,[])
}
Add(For,14344520,413,301)
{
Start=1
link(onEvent,490853:##add,[])
link(End,12595872:getVar,[])
}
Add(Hub,885081,245,301)
{
OutCount=4
link(onEvent1,14344520:doFor,[])
link(onEvent2,15466093:doData,[(343,314)(343,440)])
link(onEvent3,14303809:doFor,[(316,321)(316,587)])
link(onEvent4,13512247:doWait,[(295,328)(295,699)])
}
Add(LineBreakEx,10675697,427,546)
{
Caption="count"
Type=2
}
Add(For,14303809,420,581)
{
Start=1
link(onEvent,3351173:doOperation,[])
link(End,10675697:getVar,[])
}
Add(Random,3466891,112,112)
{
Min=5
Max=30
}
Add(Synchronize,3342322,574,112)
{
link(onSync,2950724:doAdd,[])
}
Add(DoData,15466093,441,434)
{
link(onEventData,6300903:doWork,[])
link(Data,5504863:getVar,[])
}
Add(StrCat,16352581,903,308)
{
Str1="Finished: "
link(onStrCat,9193338:doWork,[])
link(Str2,490853:##eventIndex,[(916,296)(891,296)(891,354)(769,354)])
}
Add(Hub,11666581,595,343)
{
link(onEvent1,490853:##select,[(643,349)(643,314)])
link(onEvent2,490853:doStart,[(655,356)(655,328)])
}
Add(Math,3351173,476,581)
{
OpType=1
Op2=1
link(onResult,11666581:doEvent1,[(581,587)(581,349)])
}
Add(MultiElementEx,10113316,903,490)
{
}
BEGIN_SDK
Add(EditMultiEx,9531177,21,21)
{
WorkCount=#11:CreateEvent|52:doInit=Инициализировать количество ожидаемых потоков|9:doRelease|7:doReset|
VarCount=#6:Handle|
Width=489
Height=207
link(CreateEvent,13285598:doCreate,[(206,27)(206,76)])
link(doInit,1398212:doEvent1,[(76,34)(76,83)])
link(Handle,13285598:ObjHandle,[(27,188)(223,188)])
link(doRelease,6878072:doNext,[(59,41)(59,76)])
}
Add(Events,13285598,217,70)
{
Name=""
}
Add(CounterEx,6878072,140,70)
{
Min=1
Max=999999
Default=1
Point(onThroughMax)
Point(doMax)
link(onThroughMax,13285598:doSet,[])
AddHint(-39,71,21,13,Min)
AddHint(7,71,21,13,Default)
}
Add(Hub,1398212,98,77)
{
link(onEvent1,6878072:doMax,[])
link(onEvent2,13285598:doReset,[(158,120)])
}
Add(InfoTip,7586110,21,252)
{
Info=#110:Если бы крит. секции не было бы в потоках, то она должна была бы быть внутри семафора (на уменьшение счетчика)|
Width=491
Height=39
}
END_SDK
Add(LineBreak,10971451,812,490)
{
Caption="ev"
link(Out,10113316:CreateEvent,[])
Primary=[5375141,-700,-336]
}
Add(Hub,15188141,70,119)
{
link(onEvent1,3466891:doRandomize,[])
link(onEvent2,5375141:In,[(102,132)(102,160)])
}
Add(LineBreakEx,16279675,763,511)
{
@Color=5614250
Caption="init"
}
Add(LineBreakEx,703590,812,511)
{
@Color=5614250
Caption="init"
Type=1
link(OnEvent,10113316:doInit,[(855,517)(855,503)])
}
Add(LineBreakEx,15151214,763,532)
{
@Color=16755285
Caption="rel"
}
Add(LineBreakEx,13981404,812,532)
{
@Color=16755200
Caption="rel"
Type=1
link(OnEvent,10113316:doRelease,[(865,538)(865,510)])
}
Add(InfoTip,8456654,728,462)
{
Info=#21:Реализация "семафора"|
Width=246
Height=123
}
Add(LineBreakEx,5151982,903,553)
{
@Color=11184895
Caption="H"
Type=2
}
Add(LineBreakEx,5362847,903,532)
{
@Color=11184895
Caption="H"
Type=3
link(_Data,10113316:Handle,[])
}
Add(Thread,7554984,175,301)
{
Delay=0
FastStop=0
link(onExec,885081:doEvent1,[])
}
Add(LineBreakEx,5077185,840,315)
{
@Color=16755285
Caption="rel"
}
Add(LineBreakEx,6300903,490,434)
{
@Color=5614250
Caption="init"
}
Add(LineBreakEx,5504863,441,406)
{
Caption="count"
Type=2
}
Add(InfoTip,4446107,378,238)
{
Info=#24:Создание внутренних схем|
Width=169
Height=109
}
Add(InfoTip,3376183,364,511)
{
Info=#59:Запуск потоков только когда все были созданы (во избежание)|
Width=204
Height=123
}
Add(InfoTip,4977800,378,357)
{
Info=#85:Инициализация "семафора" - просигналить, когда указаное количество потоков отработает|
Width=183
Height=123
}
Add(InfoTip,14650480,364,651)
{
Info=#32:Ожидание завершения всех потоков|
Width=400
Height=214
}
Add(Hub,10736544,812,308)
{
link(onEvent1,16352581:doStrCat,[])
link(onEvent2,5077185:doWork,[])
}
Add(LineBreakEx,9193338,959,308)
{
Caption="log"
}
Add(LineBreakEx,5903133,525,112)
{
Caption="log"
Type=1
link(OnEvent,3342322:doSynchronize,[])
}
Add(LineBreakEx,3980463,567,693)
{
Caption="log"
}
Add(DoData,9308539,469,693)
{
Data=String(Все потоки завершились)
link(onEventData,10662999:doEvent1,[])
}
Add(LineBreakEx,6051718,420,665)
{
@Color=11184895
Caption="H"
Type=2
}
Add(WaitObject,13512247,420,693)
{
link(onWait,9308539:doData,[])
link(ObjHandle,6051718:getVar,[])
}
Add(LineBreakEx,1030803,658,798)
{
Caption="destroy"
}
Add(LineBreakEx,8310483,686,315)
{
Caption="destroy"
Type=1
link(OnEvent,490853:##clear,[])
}
Add(Hub,10662999,525,693)
{
link(onEvent1,3980463:doWork,[])
link(onEvent2,8551758:doDeferredEvent,[(546,706)(546,804)])
}
Add(DeferredEvent,8551758,609,798)
{
link(onDeferredEvent,1030803:doWork,[])
}

В процессе реализации выяснилось что нет необходимости в "увеличении счетчика" каждым из потоков - только "уменьшение", а точнее, сигнал о том что поток завершился. А количество ожидаемых "завершений" задаётся один раз перед запуском потоков.

Хотя я раньше назвал этот принцип "семафором", он отличается от принципа одноименного стандартного объекта Windows. Поэтому, чтобы не было путаницы, если когда-то будет создан такой компонент, то назвать его стоит иначе.
Это как бы "условный Events" или "подсчитываемый Events".

Редактировалось 5 раз(а), последний 2019-01-12 12:32:19
карма: 19

0
Разработчик
Ответов: 25459
Рейтинг: 2070
#63: 2019-01-11 18:11:44 ЛС | профиль | цитата
Netspirit писал(а):
Вот базовая заготовка динамических потоков, как я это понял. Есть минимальная защита, но вероятно, все равно могут быть разные проблемы при более интенсивной работе потоков.

А куда идет пустой LineBreakeEx под именем 'H'?
карма: 19

0
Ответов: 3910
Рейтинг: 620
#64: 2019-01-11 18:30:14 ЛС | профиль | цитата
Там пустые брейки чисто для удобства, чтобы можно было скопировать и вставить в другие места. Их действующие копии подключены куда надо.

Редактировалось 1 раз(а), последний 2019-01-11 18:30:50
карма: 19

0
Ответов: 687
Рейтинг: 7
#65: 2019-01-11 19:28:41 ЛС | профиль | цитата
Netspirit, TCP клиент в мультипоточном режиме тоже ведет себя как динамический контейнер и всего его выходы нужно защищать сэйфмодами? Или там один поток и защищать нужно только пересечение с главным потоком?
карма: 0

0
Ответов: 3910
Рейтинг: 620
#66: 2019-01-12 12:25:03 ЛС | профиль | цитата
Внутри компонентов используется много потоков и их работа в меру моих умений реализована безопасно.
Но для автора схемы следует рассматривать клиент или сервер как просто работающий в параллельном потоке. То-есть, при AsyncEvents=True события компонента нужно обрабатывать так, как будто это один компонент Thread с событием onExec. Между собой события никогда не происходят одновременно, поэтому их между собой никак не надо "синхронизировать". Но когда они обращаются к данным, к которым есть доступ других потоков - используются те же принципы, которые были описаны ранее.
карма: 19

0
Ответов: 687
Рейтинг: 7
#67: 2019-01-12 13:42:16 ЛС | профиль | цитата
Вот так и бывает: начали с таблицы, а раскрыли самые сливки о параллельных потоках и синхронизации. Спасибо всем участникам!

Редактировалось 1 раз(а), последний 2019-01-12 13:42:29
карма: 0

0
Разработчик
Ответов: 25459
Рейтинг: 2070
#68: 2019-01-12 13:58:23 ЛС | профиль | цитата
Neo писал(а):
Спасибо всем участникам!

Похоже, что мы еще не закончили
карма: 19

0
Ответов: 687
Рейтинг: 7
#69: 2019-01-12 15:43:17 ЛС | профиль | цитата
nesco, таки похоже.
Подскажите, что не так с моей схемой? Хочу разделить безотложное чтение данных в стек и дальнейшую долгую обработку их главным потоком. Но поток с данными ждет все же основную обработку почему-то.
Это тестовая пиковая нагрузка. Она может случаться всего секунды 3 за минуту.
Add(MainForm,2953706,21,98)
{
link(onCreate,15325505:doEvent1,[])
}
Add(Thread,1595303,189,119)
{
@Hint=#45:Данные из TCP с безотложной записью в очередь|
Delay=100
link(onExec,10709922:doNext,[])
AddHint(2,42,33,13,Delay)
AddHint(-90,-57,177,26,@Hint)
}
Add(SafeMode,15768141,350,126)
{
Name="CritSection1"
link(onSafeMode,4481401:doPush,[])
AddHint(-29,37,72,13,Name)
}
Add(Label,14925684,665,140)
{
Left=80
Top=155
Width=10
Height=17
Caption="0"
}
Add(SafeMode,15450595,343,217)
{
Name="CritSection1"
link(onSafeMode,4481401:doPop,[(410,223)(410,139)])
AddHint(-29,40,72,13,Name)
}
Add(CounterEx,10709922,238,119)
{
Max=100000
link(onNext,4962318:doEvent1,[])
}
Add(Hub,15325505,112,112)
{
OutCount=4
link(onEvent2,1595303:doStart,[])
link(onEvent3,3645755:doStart,[(179,132)(179,223)])
}
Add(TimeCounter,13546177,350,63)
{
Precision=1
link(onStop,2513193:doEvent,[])
}
Add(Hub,4962318,280,119)
{
OutCount=3
link(onEvent1,13546177:doStart,[(305,125)(305,69)])
link(onEvent2,15768141:doSafeMode,[])
link(onEvent3,13546177:doStop,[(319,139)(319,76)])
}
Add(Debug,2513193,392,70)
{
WEName="Zanatost_potoka"
VDName=""
}
Add(Timer,11906121,476,175)
{
Interval=30
link(onTimer,3956007:doPop,[(529,181)(529,146)])
AddHint(-5,48,27,13,Interval)
}
Add(For,16666201,588,140)
{
@Hint=#17:Тестовая нагрузка|
End=1000
link(onEvent,6697411:doEvent,[])
AddHint(-42,46,112,13,@Hint)
}
Add(Debug,6697411,637,140)
{
WEName="Out"
VDName=""
link(onEvent,14925684:doText,[])
}
Add(Thread,3645755,231,217)
{
@Hint=#73:Читает потоком (не таймером) стек тоб не занять сейфмод долгой обработкой|
Delay=120
link(onExec,15450595:doSafeMode,[])
AddHint(-7,42,33,13,Delay)
AddHint(-66,77,198,39,@Hint)
}
Add(DeferredEvent,12176628,483,133)
{
@Hint=#30:Освобождает часть с потоками?!|
@Color=43775
InData=0
link(onDeferredEvent,3956007:doPush,[])
AddHint(-21,-44,185,13,@Hint)
}
Add(Stack,4481401,434,126)
{
link(onPop,12176628:doDeferredEvent,[])
}
Add(Timer,16388215,168,231)
{
Interval=120
AddHint(-4,41,33,13,Interval)
}
Add(Stack,3956007,539,133)
{
link(onPop,16666201:doFor,[])
}


Редактировалось 1 раз(а), последний 2019-01-12 15:54:04
карма: 0

0
Ответов: 3910
Рейтинг: 620
#70: 2019-01-12 19:24:50 ЛС | профиль | цитата
Neo, частый вызов DeferredEvent, большая вероятность пропуска событий. DeferredEvent исполняется в главном потоке, таймер возле него - тоже. На таймере "тестовая нагрузка" - главный поток занят, DeferredEvent пропускает события.
карма: 19

0
Ответов: 687
Рейтинг: 7
#71: 2019-01-13 02:53:38 ЛС | профиль | цитата
Netspirit писал(а):
DeferredEvent пропускает события

Но если вместо него поставить Synchronize (не пропускает), то это полностью нивелирует мечту о разграничении потоков.
карма: 0

0
Ответов: 3910
Рейтинг: 620
#72: 2019-01-13 15:46:57 ЛС | профиль | цитата
Именно. Зависит от задачи. Если одна часть генерирует данные, а другая не успевает их обрабатывать - значит надо решать что делать. Либо уменьшать скорость генерации данных, либо пропускать их обработку, либо куда-то складывать, чтобы обработать потом (а это "потом" может быть только тогда, когда поступление данных закончено и можно приступить к их обработке).
карма: 19

0
Ответов: 687
Рейтинг: 7
#73: 2019-01-19 02:30:54 ЛС | профиль | цитата
Разнес на 2 приложения. При первом рассмотрении задача решена. Это вообще законно?

Первичный модуль соединений (принимает данные от TCP безотложно в очередь)
Add(MainForm,4026477,266,105)
{
Caption="Первичный модуль соединений"
link(onCreate,3797376:doWork2,[(305,125)(305,34)])
}
Add(Thread,1595303,434,126)
{
@Hint=#45:Данные из TCP с безотложной записью в очередь|
Delay=100
link(onExec,10709922:doNext,[])
AddHint(2,42,33,13,Delay)
AddHint(-76,-40,177,26,@Hint)
}
Add(SafeMode,15768141,595,133)
{
Name="CritSection1"
link(onSafeMode,4481401:doPush,[])
AddHint(-34,37,72,13,Name)
}
Add(SafeMode,15450595,609,224)
{
Name="CritSection1"
link(onSafeMode,4481401:doPop,[(648,230)(648,146)])
AddHint(-29,40,72,13,Name)
}
Add(CounterEx,10709922,483,126)
{
Max=100000
link(onNext,4962318:doEvent1,[])
}
Add(Hub,15325505,357,119)
{
OutCount=4
link(onEvent1,12421006:doWork3,[(382,125)(382,97)(270,97)])
link(onEvent3,2721350:doWork2,[])
link(onEvent4,3631004:doStart,[(382,146)(382,216)(375,216)(375,230)])
}
Add(TimeCounter,13546177,595,70)
{
Precision=1
}
Add(Hub,4962318,525,126)
{
OutCount=4
link(onEvent1,13546177:doStart,[(550,132)(550,76)])
link(onEvent2,15768141:doSafeMode,[])
link(onEvent3,13546177:doStop,[(564,146)(564,83)])
link(onEvent4,9557811:doSynchronize,[(634,153)(634,83)])
}
Add(Stack,4481401,679,133)
{
Point(onEmpty)
link(onPop,8167724:doSend,[(718,146)(718,13)(445,13)(445,27)])
link(onEmpty,4570908:doWork2,[(725,153)(725,62)])
}
Add(IndexToChanel,16082010,518,224)
{
Point(Index)
link(onEvent1,6659850:doEvent1,[(557,230)(557,223)])
link(Index,3065838:State,[])
}
Add(Switch,3065838,518,168)
{
DataOn=Integer(0)
DataOff=Integer(1)
Default=0
Point(State)
Point(doOn)
}
Add(Thread,3631004,385,224)
{
Delay=120
link(onExec,13807543:doSafeMode,[])
AddHint(-47,44,33,13,Delay)
}
Add(SafeMode,4541376,567,21)
{
Name="CritSection2"
link(onSafeMode,4570908:doWork1,[(606,27)])
AddHint(55,10,72,13,Name)
}
Add(SafeMode,13807543,441,224)
{
Name="CritSection2"
WaitMode=1
link(onSafeMode,16082010:doEvent,[])
AddHint(-44,70,72,13,Name)
}
Add(Hub,6659850,574,217)
{
link(onEvent1,3065838:doReset,[(599,223)(599,209)(501,209)(501,181)])
link(onEvent2,15450595:doSafeMode,[])
}
Add(PipeClient,8167724,455,21)
{
PipeName="my"
Point(onErrorConnect)
link(onReceive,4541376:doSafeMode,[])
link(onConnect,15325505:doEvent1,[(494,41)(494,83)(347,83)(347,125)])
link(onErrorConnect,3091951:doDeferredEvent,[])
}
Add(Button,6411623,196,35)
{
Left=20
Top=15
Width=135
Caption="Генерировать 3 сек"
link(onClick,13392823:doEvent1,[])
}
Add(Button,3278153,196,70)
{
Left=20
Top=50
Width=135
Caption="Пауза"
link(onClick,8731543:doWork2,[])
}
Add(HubEx,2721350,385,133)
{
link(onEvent,1595303:doStart,[(396,139)(396,132)])
}
Add(HubEx,4570908,602,56)
{
Angle=2
link(onEvent,3065838:doOn,[(508,62)(508,188)])
}
Add(Synchronize,9557811,756,77)
{
link(onSync,5990075:doText,[])
}
Add(Label,5990075,812,77)
{
Left=175
Top=20
Caption="Количество"
}
Add(HubEx,3797376,427,28)
{
link(onEvent,8167724:doConnect,[])
}
Add(DeferredEvent,3091951,504,49)
{
Delay=1000
link(onDeferredEvent,3797376:doWork3,[(543,55)(543,69)(431,69)])
}
Add(Timer,13611684,280,42)
{
Enable=1
AutoStop=3
link(onTimer,8731543:doWork1,[(333,48)])
}
Add(Hub,13392823,245,35)
{
link(onEvent1,2721350:doWork1,[(389,41)])
link(onEvent2,12421006:doWork2,[])
}
Add(HubEx,8731543,329,70)
{
link(onEvent,1595303:doStop,[(403,76)(403,139)])
}
Add(HubEx,12421006,266,42)
{
link(onEvent,13611684:doTimer,[])
}


Основная обработка очереди
Add(MainForm,2953706,21,105)
{
Caption="Основная обработка очереди"
link(onCreate,9654003:doStartServer,[(60,125)(60,104)])
}
Add(Label,14925684,686,266)
{
Left=80
Top=155
Width=10
Height=17
Caption="0"
}
Add(Timer,11906121,329,259)
{
Interval=30
link(onTimer,5810077:doCompare,[])
AddHint(-25,50,27,13,Interval)
}
Add(For,16666201,609,266)
{
@Hint=#17:Тестовая нагрузка|
End=1000
link(onEvent,14925684:doText,[])
AddHint(0,45,112,13,@Hint)
}
Add(Memory,13238423,434,175)
{
Default=String(obrabotano)
}
Add(Hub,2650613,483,259)
{
OutCount=4
link(onEvent1,13987857:doData,[(508,265)(508,237)])
link(onEvent2,16666201:doFor,[])
link(onEvent3,10709922:doNext,[])
link(onEvent4,9654003:doSendAll,[(508,286)(508,300)(186,300)(186,125)])
}
Add(StrMask,5810077,434,259)
{
Mask="obrabotano"
link(onFalse,2650613:doEvent1,[])
link(Str,13238423:Value,[])
}
Add(HubEx,1814196,406,175)
{
link(onEvent,13238423:doValue,[])
}
Add(DoData,13987857,518,231)
{
Data=String(obrabotano)
link(onEventData,1814196:doWork3,[(557,237)(557,223)(410,223)])
}
Add(PipeServer,9654003,196,91)
{
PipeName="my"
AsyncEvents=0
Point(doSendAll)
link(onReceive,1814196:doWork2,[(242,97)(242,181)])
}
Add(Label,5437382,588,350)
{
Left=80
Top=130
Caption="Количество"
}
Add(CounterEx,10709922,525,273)
{
Max=100000
link(onNext,5437382:doText,[(578,279)(578,356)])
}


Редактировалось 1 раз(а), последний 2019-01-19 02:33:56
карма: 0

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