Вверх ↑
Этот топик читают: Гость
Ответов: 1926
Рейтинг: 172
#1: 2017-12-13 11:09:55 ЛС | профиль | цитата
Хочу сделать многопоточную загрузку файлов. Алгоритм такой:
1. Первый поток двигает счётчик, извлекает ссылку и начинает загрузку.
2. Второй поток параллельно делает то же самое.

Но вот вопрос: не будет ли ошибок и конфликтов, если два потока долбятся в одну схему? У меня в схеме счётчик и получение ссылки и имени локального файла - общие для обоих потоков, так вот как защитить этот участок, чтобы второй поток не ломанулся туда, пока первый не отработал?

Я составил вот так:

Add(MainForm,2953706,84,84)
{
Position=1
}
Add(Thread,16117486,231,168)
{
Delay=0
FastStop=0
link(onExec,8479595:doEvent1,[])
}
Add(Math,9808350,651,168)
{
@Hint=#35:Счётчик для перебора строк в списке|
Op2=1
ResultType=0
Default=-1
Point(doClear)
link(Op1,1795754:Var1,[(657,156)(648,156)(648,215)])
}
Add(If_else,450274,651,266)
{
Type=3
link(onTrue,13588247:doRead,[])
link(Op1,1795754:Var2,[])
link(Op2,16699030:EndIdx,[])
}
Add(GetDataEx,1795754,651,210)
{
link(Data,9808350:Result,[])
}
Add(ArrayRW,13588247,714,266)
{
link(onRead,6155442:Method,[(762,272)(762,275)])
link(Array,16699030:Array,[])
link(Index,1795754:Var3,[(727,215)])
}
Add(HTTP_Get,15481560,714,462)
{
Wait=0
link(onStop,14082066:doEvent1,[])
link(URL,7003931:Value,[])
link(FileName,494180:Value,[])
}
Add(Hub,14082066,763,483)
{
OutCount=3
link(onEvent3,757926:doDeferredEvent,[])
}
Add(LineBreak,5489820,280,175)
{
Caption="re"
link(Out,8479595:doEvent2,[])
Primary=[10910484,560,322]
}
Add(DeferredEvent,757926,798,497)
{
link(onDeferredEvent,10910484:In,[])
}
Add(Hub,12653916,567,168)
{
InCount=3
link(onEvent1,9808350:doOperation,[])
link(onEvent2,450274:doCompare,[(593,181)(593,272)])
}
Add(Memory,494180,721,420)
{
Point(Data)
link(Data,13273961:Var2,[])
}
Add(Memory,7003931,714,350)
{
Point(Data)
link(onData,494180:doValue,[(758,356)(758,391)(709,391)(709,426)])
link(Data,1580071:Var2,[])
}
Add(Hub,15593223,441,168)
{
link(onEvent1,12653916:doEvent1,[])
link(onEvent2,13787866:In,[])
}
Add(LineBreak,13879588,672,350)
{
link(Out,7003931:doValue,[])
Primary=[13787866,-203,-175]
}
Add(Hub,8479595,322,168)
{
InCount=2
OutCount=3
link(onEvent1,13202732:doSafeMode,[])
link(onEvent3,14132148:In,[(343,188)(343,195)])
}
Add(SafeMode,13202732,392,168)
{
link(onSafeMode,15593223:doEvent1,[])
}
Add(Thread,935624,231,259)
{
Delay=0
FastStop=0
link(onExec,10619640:doEvent1,[])
}
Add(Hub,10619640,322,259)
{
InCount=2
OutCount=3
link(onEvent1,9555098:doSafeMode,[])
link(onEvent3,10942780:In,[(343,279)(343,286)])
}
Add(SafeMode,9555098,392,259)
{
link(onSafeMode,3015750:doEvent1,[])
}
Add(Hub,3015750,441,259)
{
link(onEvent1,12653916:doEvent2,[(511,265)(511,181)])
link(onEvent2,13515872:In,[])
}
Add(LineBreak,15146009,665,462)
{
Caption="dwn"
link(Out,15481560:doDownload,[])
Primary=[14132148,-315,-273]
}
Add(HTTP_Get,277648,546,686)
{
Wait=0
link(onStop,7011035:doEvent1,[])
link(URL,946856:Value,[])
link(FileName,16729224:Value,[])
}
Add(Hub,7011035,595,707)
{
OutCount=3
link(onEvent3,13485263:doDeferredEvent,[])
}
Add(LineBreak,548609,280,266)
{
Caption="re"
link(Out,10619640:doEvent2,[])
Primary=[8674877,392,455]
}
Add(DeferredEvent,13485263,630,721)
{
link(onDeferredEvent,8674877:In,[])
}
Add(Memory,16729224,553,644)
{
Point(Data)
link(Data,13273961:Var1,[(559,404)])
}
Add(Memory,946856,546,574)
{
Point(Data)
link(onData,16729224:doValue,[(590,580)(590,615)(541,615)(541,650)])
link(Data,1580071:Var1,[(552,327)])
}
Add(LineBreak,11839327,504,574)
{
link(Out,946856:doValue,[])
Primary=[13515872,-35,-308]
}
Add(LineBreak,9040062,497,686)
{
Caption="dwn"
link(Out,277648:doDownload,[])
Primary=[10942780,-147,-406]
}
Add(GetDataEx,1580071,714,322)
{
link(Data,13588247:Item,[])
}
Add(ListBox,16699030,700,147)
{
Left=110
Top=10
Width=150
Height=235
Strings=#1:1|1:2|1:3|1:4|1:5|
Point(EndIdx)
}
Add(Button,5052351,91,168)
{
Left=30
Top=20
link(onClick,9075221:doEvent1,[])
}
Add(Hub,9075221,147,168)
{
link(onEvent1,16117486:doStart,[])
link(onEvent2,935624:doStart,[(196,181)(196,265)])
}
Add(PointHint,6155442,777,259)
{
Info=#28:Тут формирование имени файла|
Width=190
}
Add(GetDataEx,13273961,721,399)
{
Angle=1
link(Data,6155442:Var,[(872,404)])
}

1. Можно ли вообще использовать так компонент SafeMode?
2. Видел компоненты Mutex и MutexThread, но как их вообще использовать? Можно пример?
3. Имеет ли смысл после закачки использовать DeferredEvent, как у меня в схеме?
карма: 9
0
Ответов: 4629
Рейтинг: 749
#2: 2017-12-13 12:38:45 ЛС | профиль | цитата
Вроде всё правильно сделал с SafeMode. Рекомендую всё же LineBreak-ам давать различные имена, чтобы более понятно было.
3042 писал(а):
3. Имеет ли смысл после закачки использовать DeferredEvent, как у меня в схеме?
Смотря для чего. DefferedEvent выдаёт событие в главном потоке приложения, что при задаче работы в параллельном потоке не имеет смысла. Ты используешь его для повторения операции - вместо него нужно либо ставить Repeat с 1=1 сразу после Thread.onExec, либо ставить Thread.FastStop=False, Thread.Delay=1, что аналогично Repeat.
карма: 26

0
Ответов: 1926
Рейтинг: 172
#3: 2017-12-13 14:15:52 ЛС | профиль | цитата
Netspirit, спасибо.

В принципе, вместо SafeMode можно использовать глобальную переменную (в пределах одной программы):
Add(MultiElement,14563708,455,189)
{
}
BEGIN_SDK
Add(EditMulti,8200801,21,21)
{
EventCount=1
WorkCount=1
link(doWork1,9867460:doWork2,[(53,27)(53,111)])
}
Add(GlobalVar,3034072,147,56)
{
Name="_mutex"
Data=Integer(0)
}
Add(IndexToChanel,5837253,147,105)
{
Point(Index)
link(onEvent1,7475528:doEvent1,[])
link(onEvent2,9867460:doWork3,[(191,118)(191,143)(137,143)])
link(Index,3034072:Var,[])
}
Add(ChanelToIndex,889370,105,56)
{
link(onIndex,3034072:doValue,[])
}
Add(Hub,7475528,203,105)
{
OutCount=3
link(onEvent1,889370:doWork2,[(229,111)(229,92)(96,92)(96,69)])
link(onEvent2,8200801:onEvent1,[(269,118)(269,27)])
link(onEvent3,889370:doWork1,[(234,125)(234,97)(89,97)(89,62)])
}
Add(HubEx,9867460,133,105)
{
link(onEvent,5837253:doEvent,[])
}
END_SDK

Но это так, изыск...

Ещё вопрос: компонент MutexThread - это смесь Thread и SafeMode? Т.е. второй MutexThread с таким же PrefixName, как у первого, не запустится, пока первый MutexThread не отработает, я правильно понимаю?

Мало сведений и примеров по компонентам: Mutex, MutexThread, Events, WaitObject.

Редактировалось 1 раз(а), последний 2017-12-13 14:17:34
карма: 9
0
Ответов: 1926
Рейтинг: 172
#4: 2017-12-14 19:54:22 ЛС | профиль | цитата
Ещё интересует понимание вот такой схемы:

Add(Thread,8280122,434,196)
{
Delay=0
FastStop=0
link(onExec,1687806:doDeferredEvent,[])
}
Add(Button,10120159,252,196)
{
Left=5
Top=20
Caption="вкл"
link(onClick,16770749:doEvent1,[])
}
Add(DeferredEvent,1687806,490,196)
{
}
Add(Thread,3970021,434,245)
{
Delay=0
FastStop=0
link(onExec,1645210:doDeferredEvent,[])
}
Add(DeferredEvent,1645210,490,245)
{
}
Add(Hub,16770749,308,196)
{
link(onEvent1,8280122:doStart,[])
link(onEvent2,3970021:doStart,[(378,209)(378,251)])
}

Два потока тут исполняются параллельно. А вот после DefferedEvents параллельность сохраняется или всё же события onDeferredEvent встают в очередь друг за другом?
карма: 9
0
Ответов: 4629
Рейтинг: 749
#5: 2017-12-15 12:51:03 ЛС | профиль | цитата
События после DefferedEvent попадают в главный поток и выполняются одно за другим главным потоком. При этом параллельные потоки продолжают исполнение сразу (метод doDefferedEvent возвращает управление), а событие onDefferedEvent - "когда-то потом", в т.ч. конфликтуя с породившими его потоками.
карма: 26

0
Ответов: 1926
Рейтинг: 172
#6: 2017-12-15 19:53:20 ЛС | профиль | цитата
Netspirit, спасибо. Плюсик не могу поставить - лишён очков.
А вот ещё вопрос: почему такая схема не выводит сообщение? Почему таймер не работает в потоке?

Add(Thread,12578108,315,343)
{
Delay=0
FastStop=0
link(onExec,16683636:doTimer,[])
}
Add(Timer,16683636,406,343)
{
Interval=1
Enable=1
AutoStop=1
link(onTimer,6441049:doMessage,[])
}
Add(Button,5158431,266,343)
{
Left=15
Top=80
link(onClick,12578108:doStart,[])
}
Add(Message,6441049,455,343)
{
Message="2"
}
карма: 9
0
Ответов: 4629
Рейтинг: 749
#7: 2017-12-16 15:41:41 ЛС | профиль | цитата
А тут следует знать такое. Сообщения от окон обрабатываются очередью сообщений потока. А как система знает в очередь какого потока направить сообщение? Установлено такое правило: сообщения для окна может получить только тот поток, который создал окно. Следовательно, если какой-то поток создаёт окно, он же должен после этого запустить цикл выборки сообщений из своей очереди до окончания жизни всех созданных им окон. Например, при старте приложения существует только один поток (назовём его главным), в котором и создается первая форма приложения и запускается обработка сообщений этой формы. Если не создавать дополнительных потоков, то в дальнейшем все остальные окна тоже принадлежат главному потоку и их сообщения тоже обрабатывает он.
Компонент Timer основан на сообщениях, поэтому разделяет это поведение. По методу doTimer создаётся системный объект таймера и предполагается, что создавший его поток должен обрабатывать его сообщения. Можно немного пошаманить и убедиться в этом: поставь через хаб после doTimer метод компонента Application.doProcessMessages - этот метод вызывает ту же выборку и обработку сообщений, которая происходит в нашем главном потоке, но поскольку вызывается из параллельного потока, то обрабатываются только сообщения из очереди данного потока.

Предполагаю, так же работает функция MessageBox, показывающая окно из любого потока: она создаёт окно, затем запускает цикл обработки сообщений для этого окна и не возвращает управления, пока окно не закроется.

Существуют некоторые broadcast сообщения (не связанные с окнами), которые попадают во все очереди сообщений.

Есть ещё компонент MMTimer, основанный на параллельном потоке, а не оконных сообщениях, который не подвержен данному поведению. Ну, а чтобы всё-таки включить обычный таймер, нужно метод doTimer вызвать из главного потока, для чего применяется компонент Synchronize.

Редактировалось 2 раз(а), последний 2017-12-18 11:53:17
карма: 26

1
Голосовали:flint2
Ответов: 1926
Рейтинг: 172
#8: 2017-12-16 22:55:41 ЛС | профиль | цитата
Netspirit, ещё раз спасибо!
карма: 9
0
8
Сообщение
...
Прикрепленные файлы
(файлы не залиты)