Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.02.26;
Скачать: CL | DM;

Вниз

Вопрос по потокам.   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.044 c
15-1138969362
Pazitron_Brain
2006-02-03 15:22
2006.02.26
Процените сайт!


15-1138794216
Сергей Ю.
2006-02-01 14:43
2006.02.26
Delphi перестал запускаться. Ругается на rtl60.bpl


15-1139082481
Труп Васи Доброго
2006-02-04 22:48
2006.02.26
RXMemoryData


15-1138586750
vidiv
2006-01-30 05:05
2006.02.26
Борьба со спамерами


5-1125637913
DimaBr
2005-09-02 09:11
2006.02.26
Слетает события компонента