Форум: "Начинающим";
Текущий архив: 2006.02.26;
Скачать: [xml.tar.bz2];
ВнизВопрос по потокам. Найти похожие ветки
← →
dabreezy (2006-02-07 18:57) [0]Добрый вечер.
У меня такой вопрос по потокам (целый день башку ломаю)
есть процедура запуска потока (в ней цикл с сложными вычислениями):
procedure TMyThread1.Execute;
begin
...
repeat
until (terminated) or (i1=i-1);
...
synchronize (Thread_done);
end;
Далее функция Thread_done (thread_running - кол-во потоков):
procedure TMyThread1.Thread_done;
begin
form1.thread_running:=form1.thread_running-1;
end;
Так вот такая штука получается, когда все потоки завершены, то получается что иногда работает нормально(thread_runnig=0), а иногда thread_running=1 или 2. Причем чем больше потоков, тем чаще такое бывает! При 3х-6 потоков такое практически не бывает.
Объясните пожалуйста в чем дело.
← →
Zeqfreed © (2006-02-07 19:08) [1]У класса TThread есть специальное событие OnTerminate, возникающее после отработки метода Execute. А вообще, в приведенном коде, вроде нет ошибок.
← →
Defunct © (2006-02-07 19:11) [2]оповещайте форму о завершении из потока с помощью PostMessage. В обработчике сообщения уменьшайте переменную thread_runnung.
← →
dabreezy (2006-02-07 19:17) [3]
> Zeqfreed © (07.02.06 19:08) [1]
> У класса TThread есть специальное событие OnTerminate,
И так пробовал не работает :(
← →
dabreezy (2006-02-07 19:19) [4]
> Defunct © (07.02.06 19:11) [2]
> оповещайте форму о завершении из потока с помощью PostMessage.
> В обработчике сообщения уменьшайте переменную thread_runnung.
>
А как это сделать?
← →
Zeqfreed © (2006-02-07 19:22) [5][2] Defunct © (07.02.06 19:11)
А чем это лучше обычного вызова метода формы в контексте основного потока?
dabreezy (07.02.06 18:57)
Все-таки мне кажется, что ошибка где-то в другом месте. Не в том коде, что Вы привели.
← →
dabreezy (2006-02-07 19:34) [6]
> Zeqfreed © (07.02.06 19:22) [5]
Так в том то и все дело, что synchronize (Thread_done); выполняется прямо перед концом функции. Должно вроде нормально работать, оно иногда и работает. Причем даже пробовал следующее: делал переменную у каждого потока flag. В начале функции flag=0, а в конце flag=1, все равно не помогает
← →
Leonid Troyanovsky © (2006-02-07 19:40) [7]
> dabreezy (07.02.06 19:34) [6]
> Так в том то и все дело, что synchronize (Thread_done);
> выполняется прямо перед концом функции. Должно вроде нормально
> работать, оно иногда и работает. Причем даже пробовал следующее:
Нормально должно работать в OnTerminate, при условии, конечно,
что thread_runnung инкрементируется правильно.
--
Regards, LVT.
← →
Defunct © (2006-02-07 19:42) [8]Zeqfreed © (07.02.06 19:22) [5]
Хотя бы тем что не потребуется использовать Synchronize
dabreezy (07.02.06 19:19) [4]
> А как это сделать?
например так:
в модуле описанием потока:const WM_THREADDONE = WM_USER + 1;
type
TMyThread = class(TThead)
...
protected
FOwnerWnd : HWND;
procedure Execute;
public
constructor Create( AOwnerWND: HWND);
end;
constructor TMyThread.Create;
begin
inherited Create( true );
FOwnerWND := AOwnerWND;
...
resume;
end;
procedure TMyThread.Execute;
begin
...
PostMessage( FOwnerWND, WM_THREADDONE, 0, 0);
end;
в модуле с формой:TForm1 = class(TForm)
...
procedure ThreadDoneHandler( var Msg: TMessage);message WM_THREADDONE;
procedure StartThread;
end;
procedure TForm1.ThreadDoneHandler;
begin
dec( Thread_running )
end;
procedure StartThread;
begin
try
TMyThread.Create( Handle );
inc( Thread_running );
except
ShowMessage(" could not start new thread" )
end;
end;
← →
dabreezy (2006-02-07 19:45) [9]
>
> Нормально должно работать в OnTerminate, при условии, конечно,
>
> что thread_runnung инкрементируется правильно.
Я запускаю потоки вот так:
Thread_array: array [1..50] of TMyThread1;
...
thread_kol:=25;
thread_running:=thread_kol;
for i:=1 to Thread_kol do
begin
Thread_array[i]:=TMyThread1.Create(false);
Thread_array[i].str:=inttostr(i);
end;
Соответственно точно известно что потоков запущено 25. Вот от thread_running и отнимается по единице когда какой-нибуть поток остановлен.
← →
Leonid Troyanovsky © (2006-02-07 19:48) [10]
> Leonid Troyanovsky © (07.02.06 19:40) [7]
> Нормально должно работать в OnTerminate, при условии, конечно,
> что thread_runnung инкрементируется правильно.
И при условии, что потокам не делают TerminateThread.
--
Regards, LVT.
← →
dabreezy (2006-02-07 19:50) [11]
> Leonid Troyanovsky © (07.02.06 19:48) [10]
>
> > Leonid Troyanovsky © (07.02.06 19:40) [7]
>
> > Нормально должно работать в OnTerminate, при условии,
> конечно,
> > что thread_runnung инкрементируется правильно.
>
>
> И при условии, что потокам не делают TerminateThre
А кто это может делать? Windows? В программе ничего такого не делается.
← →
dabreezy (2006-02-07 19:51) [12]
> Defunct © (07.02.06 19:42) [8]
> Zeqfreed © (07.02.06 19:22) [5]
> Хотя бы тем что не потребуется использовать Synchronize
>
> dabreezy (07.02.06 19:19) [4]
> > А как это сделать
Спасибо большое. Попробую. Надеюсь получится
← →
Leonid Troyanovsky © (2006-02-07 19:52) [13]
> dabreezy (07.02.06 19:45) [9]
> Соответственно точно известно что потоков запущено 25.
Точнее было б делать inc(thread_running) в конце цикла.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2006-02-07 19:56) [14]
> dabreezy (07.02.06 19:50) [11]
> > И при условии, что потокам не делают TerminateThre
> А кто это может делать? Windows? В программе ничего такого
> не делается.
Это может сделать любой, у кого есть хендл потока.
Но, кажется мне, что собака рылась в другом.
Покажи OnTerminate.
--
Regards, LVT.
← →
dabreezy (2006-02-07 20:10) [15]> Это может сделать любой, у кого есть хендл потока.
> Но, кажется мне, что собака рылась в другом.
> Покажи OnTerminate.
Пробовал делать так:
в объявлении класса формы:
private
procedure Thread_Done(Sender: TObject);
в цикле
thread_kol:=25;
for i:=1 to Thread_kol do
begin
Thread_array[i]:=TMyThread1.Create(false);
Thread_array[i].str:=inttostr(i);
Thread_array[i].OnTerminate:=Thread_done;
inc(Thread_running);
end;
procedure TForm1.Thread_done(Sender: TObject);
begin
Dec(Thread_running);
if thread_running=0 then
begin
...
end;
end;
← →
begin...end © (2006-02-07 20:12) [16]> Defunct © (07.02.06 19:42) [8]
> Хотя бы тем что не потребуется использовать Synchronize
А что плохого в использовании Synchronize?
← →
YuRock © (2006-02-07 21:39) [17]
> А что плохого в использовании Synchronize?
Ну хотя бы добавление необязательных тормозов из-за критических секций и wait"ов, которые использует этот метод.
Если не нужна синхронность (а она тут вряд-ли нужна - я телепат :), то лучший вариант - PostMessage.
← →
begin...end © (2006-02-07 21:46) [18]> YuRock © (07.02.06 21:39) [17]
Я просто не понял, чем Synchronize хуже PostMessage в контексте проблемы автора.
← →
YuRock © (2006-02-07 22:05) [19]
> Я просто не понял, чем Synchronize хуже PostMessage в контексте
> проблемы автора.
Так более просто, а значит - надежно. И быстрее. А это лучше в любом контексте.
← →
Defunct © (2006-02-08 01:40) [20]> А что плохого в использовании Synchronize?
вести с вами диалог мне не доставляет удовольствия, к тому же у вас есть "знак отличия", который дает мне понять, что темой вы прекрастно владеете.
← →
Defunct © (2006-02-08 02:36) [21]/offtop
2 begin...end
я често сказать, не знаю, как множно с вами общаться. почти во всех ветках с вашим участием наблюдаю с вашей стороны желание поставить меня в неловкое положение или как это называется на базарном языке желание "подколоть". Поэтому если хотите вести конструктивный диалог со мной, то для начала высказывайте свою точку зрения, а потом задавайте вопрос. В данном случае я не буду отвечать на ваш вопрос до тех пор пока вы не расскажете всем чем в контексте вопроса автора применение Synchronize + обращения к глобальным переменным лучше или сравнимо с PostMessage. В дальнейшем я буду игнорировать все ваши двусмысленные ("короткие") сообщения в мой адрес, как потенциально опасные для меня.
← →
Leonid Troyanovsky © (2006-02-08 08:41) [22]
> dabreezy (07.02.06 20:10) [15]
> Пробовал делать так:
Так - уже лучше. Хотя, конечно, еще лучше было б
Thread_array[i]:=TMyThread1.Create(True), с завершающим Resume,
бо между Create и назначением OnTerminate может случиться немало
колов времени.
Ну, и, наконец, а как определяется то, что все потоки завершились
(в то время, как thread_running > 0) ?
--
Regards, LVT.
← →
dabreezy (2006-02-08 08:51) [23]
> Leonid Troyanovsky © (08.02.06 08:41) [22]
>
> > dabreezy (07.02.06 20:10) [15]
>
> > Пробовал делать так:
>
>
> Так - уже лучше. Хотя, конечно, еще лучше было б
> Thread_array[i]:=TMyThread1.Create(True), с завершающим
> Resume,
> бо между Create и назначением OnTerminate может случиться
> немало
> колов времени.
>
> Ну, и, наконец, а как определяется то, что все потоки завершились
>
> (в то время, как thread_running > 0) ?
Да, так работает вроде лучше, сейчас тестирую. thread_running проверяется в процедуре обработки onterminate.
Кстати вчера долго тестировал, оказалось, что программа глючила(т.е. оставался один не завершенный поток) из-за того что 1 из 25 потоков, а то и 2 не запускались вообще(проверил это просто, сделал что каждый поток создавал уникальный файл) и вот когда программа глючила как раз файлов было не 25 а 24. Когда работала нормально то файлов было 25. Может это как раз и происходило из-за того что :"Create и назначением OnTerminate может случиться немало колов времени."?
← →
evvcom © (2006-02-08 09:10) [24]
> Может это как раз и происходило из-за того что :"Create
> и назначением OnTerminate может случиться немало колов
> времени."?
Легко. Добавлю к тому, что Inc(thread_running) лучше сделать между Create и Resume.
← →
Leonid Troyanovsky © (2006-02-08 09:18) [25]
> dabreezy (08.02.06 08:51) [23]
> Может это как раз и происходило из-за того что :"Create
> и назначением OnTerminate может случиться немало колов
> времени."?
Если вчерашнее тестирование проводилось с приведенным кодом и
OnTerminate, а 1 из файлов не создавался (т.е., поток не стартовал),
то, видимо, причина не в этом.
Вообще-то, кроме ранее рассмотренного, на наблюдаемую картину
могут повлиять :
- молчаливые исключения типа EAbort в конструкторе потока;
- любые исключения в Execute: поток завершится, а до Synchronize(..)
дело не дошло (однако, OnTerminate будет выполнен).
--
Regards, LVT.
← →
dabreezy (2006-02-08 10:44) [26]
> Leonid Troyanovsky © (08.02.06 09:18) [25]
>
> > dabreezy (08.02.06 08:51) [23]
>
> > Может это как раз и происходило из-за того что :"Create
>
> > и назначением OnTerminate может случиться немало колов
>
> > времени."?
>
>
> Если вчерашнее тестирование проводилось с приведенным кодом
> и
> OnTerminate, а 1 из файлов не создавался (т.е., поток не
> стартовал),
> то, видимо, причина не в этом.
>
> Вообще-то, кроме ранее рассмотренного, на наблюдаемую картину
>
> могут повлиять :
> - молчаливые исключения типа EAbort в конструкторе потока;
>
> - любые исключения в Execute: поток завершится, а до Synchronize(.
> .)
> дело не дошло (однако, OnTerminate будет выполнен).
>
> --
> Regards, LVT.
Спасибо за ответы. Сейчас тестирую, даже с 50 потоками работает как часы :)
← →
begin...end © (2006-02-08 13:20) [27]> Defunct © (08.02.06 02:36) [21]
> Поэтому если хотите вести конструктивный диалог со мной,
> то для начала высказывайте свою точку зрения, а потом задавайте
> вопрос.
Я сам решаю, когда мне высказывать свою точку зрения, и высказывать ли её вообще. Если же в обсуждении какое-то сообщение вызывает у меня вопрос и я хочу его задать, я его задаю (что я и сделал в этой ветке). Отвечать или нет -- разумеется, личное дело того, кому этот вопрос адресуется. И если кто-то за обычным уточняющим вопросом видит желание "подколоть", то это его проблемы.
> В дальнейшем я буду игнорировать все ваши двусмысленные
> ("короткие") сообщения в мой адрес, как потенциально опасные
> для меня.
No comments.
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2006.02.26;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.047 c