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

Вниз

Проблема в многопоточном приложении: завершение потоков.   Найти похожие ветки 

 
DVM ©   (2005-12-21 15:19) [0]

Имеется многопоточное приложение:
На главной форме динамически создаются 16 комонентов, потомков TCustomControl. Каждый компонент создает при старте новый поток и запоминает его в одном из своих полей. Задача потока - получать данные в спец буфер (неважно откуда) и на основании этих данных производить рисование на канве своего компонента.
Собственно рисование и получение данных проблем не вызывает, проблема с завершение потоков.
Иногда потоки завершаются нормально, иногда сыпятся ошибки (неправильный указатель и прочие).

Вот деструктор компонента:

destructor TMyComponent.Destroy;
begin
 if Assigned(FThread) then
   begin
     FThread.Terminate;
   end;
 FBitmap.Free;
 FBuffer.Free;
 inherited Destroy;
end;

Соответственно в Execute потока написано ----------------

procedure TMyThread.Execute;
begin
 FreeOnTerminate := true;
 while not Terminated do
 begin
   ....
   Synchronize(paint);
   sleep(5);
   ....
 end;
end;

Метод Paint -----------------------------

procedure TMyThread.Paint;
begin
 ....здесь рисование и пр с использованием IntelJpeg
end;

-----------------------------------------------------
-----------------------------------------------------

Вопросы:

Почему после вызова FThread.Terminate; нельзя добавить FThread.WaitFor; ? Пишет неверный дискриптор. Но необходимо ждать завершения потока, перед удалением буфера и битмапа, т.к. он с ними работает.
Если написать: WaitForSingleObject(FThread.Handle, INFINITE);
То иногда поток завершается, иногда все висит на этой строке без движения.

В чем дело может быть? Как мне дождаться завершения потока?


 
DVM ©   (2005-12-21 15:23) [1]

Причем подмечено, что если создавать не 16 компонентов, а меньше, то все завершается чаще нормально (меньше компонентов - работает лучше), причем при наличии всего одного компонента - поток завершается всегда удачно и без ошибок.

Мне кажется дело в синхронизации потоков, только вот не пойму где именно.


 
Digitman ©   (2005-12-21 15:29) [2]


> Каждый компонент создает при старте


Что такое "старт компонента" ?


 
DVM ©   (2005-12-21 15:41) [3]


> Что такое "старт компонента" ?

Хм. неверно я выразился:

MyComponent:=TMyComponent.Create(frmMain);


 
Digitman ©   (2005-12-21 15:45) [4]

как ты понимаешь себе работу строчки

FThread.Terminate;

?


 
Alexander Panov ©   (2005-12-21 15:52) [5]

DVM ©   (21.12.05 15:19)
procedure TMyThread.Execute;
begin
FreeOnTerminate := true;


Разберись вот с этими строками.
И, соответственно, вот с этой:
if Assigned(FThread) then
  begin
    FThread.Terminate;
  end;

WaitFor возможно только если FreeOnTerminate := False;

if Assigned(FThread) then а после уничтожения потока FThread где-то обнуляется?


 
DVM ©   (2005-12-21 16:05) [6]


> как ты понимаешь себе работу строчки
>
> FThread.Terminate;

Также как и ты, я думаю. У потока выставляется флаг завершения, на который он при желании должен прореагировать.


> WaitFor возможно только если FreeOnTerminate := False;

А вот это я как то пропустил.


> if Assigned(FThread) then а после уничтожения потока FThread
> где-то обнуляется?

Нет не обнуляется. А причем здесь это?


 
Alexander Panov ©   (2005-12-21 16:21) [7]

DVM ©   (21.12.05 16:05) [6]
Нет не обнуляется. А причем здесь это?


Если поток завершится раньше, чем будет вызван метод Destroy для TMyComponent, получишь AV.


 
DVM ©   (2005-12-21 16:26) [8]


> Если поток завершится раньше, чем будет вызван метод Destroy
> для TMyComponent

Но его ведь и надо завершать до уничтожения компонента.
Ведь компонент у меня определен примерно так:

TMyComponent = class(TCustomControl)
 private
   FThread: TMyThread;    
 ...
end;

Разве я не должен уничтожать поток в деструкторе компонента?


 
Digitman ©   (2005-12-21 16:40) [9]


> Также как и ты, я думаю. У потока выставляется флаг завершения,
>  на который он при желании должен прореагировать.


совершенно верно.

что дальше ?

предположим, у потока-объекта успешно выставлено это св-во ... сие означает не иначе как тот факи, что в момент выставления этого св-ва объект был "скорее жив чем мертв" ..

и ГДЕ ты дожидаешься и фиксируешь ФАКТ уничтожения объекта-потока ПОСЛЕ того как ты установил ему этот флаг ?


 
DVM ©   (2005-12-21 16:47) [10]


> и ГДЕ ты дожидаешься и фиксируешь ФАКТ уничтожения объекта-
> потока ПОСЛЕ того как ты установил ему этот флаг ?

Так в том то и был вопрос. Из-за FreeOnTerminate := true; я не мог использовать

if Assigned(FThread) then
 begin
   FThread.Terminate;
   FThread.WaitFor; // <<--- этой строки не было.
 end;
 ..... Здесь поток уничтожен ......
 ..... теперь можно уничтожать то с чем он работал ....


 
Digitman ©   (2005-12-21 16:52) [11]


> Из-за FreeOnTerminate := true


тебя кто-то обязал эту глюконосную фичу пользовать ?


 
Digitman ©   (2005-12-21 16:53) [12]


> Из-за FreeOnTerminate := true


тебя кто-то обязал эту глюконосную фичу пользовать ?


 
Набережных С. ©   (2005-12-21 16:58) [13]


>DVM ©

А чем гарантируется, что на момент вызова TMyComponent.Destroy поток не находится внутри Synchronize(paint)? То есть, что он не ждет, когда главный поток не отработает запрошенный этим доп. потоком синхронный вызов?

И как праильно заметил Alexander Panov ©, при FreeOnTerminate = true с ожиданием нужно быть аккуратным. Как минимум, не использовать TThread.WaitFor и запомитать хендл потока до вызова Terminate. Раз уж ждать необходимо, то лучше отказаться от автоуничтожения. А раз используется синхронизация, то ждать надо с помощью MsgWaitFor...


 
DVM ©   (2005-12-21 17:00) [14]


> тебя кто-то обязал эту глюконосную фичу пользовать ?

Да нет, сам по глупости написал, пототом забыл, так и осталось. А я ее в упор не видел.

Мда....
Только проблема осталась.
При уничтожении в цикле 16 экземпляров моего компонента на Некторых из них ИНОГДА выскакивает "Неправильный указатель".

Дело в том, что написано в Synchronize потока.

Там написано следующее:

procedure TMyThread.Paint;
begin
  LoadBmpFromJpegInMemory(FMyComponent.FBitmap, FMyComponent.FBuffer.Extract(FMyComponent.content_length), FMyComponent.content_length, true, ijlFullSize);
FMyComponent.Canvas.StretchDraw(Rect(0, 0, FMyComponent.Width, FMyComponent.Height), FMyComponent.FBitmap);
end;

если Synchronize не вызывать - ошибки нет.
Непонятно, почему ошибка, .т.к. на момент вызыва этих функций все с чем они работают ЕЩЕ существует.


 
Digitman ©   (2005-12-21 17:13) [15]

что говорит отладчик ?



Страницы: 1 вся ветка

Текущий архив: 2006.01.29;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.05 c
1-1135201419
Destroyer
2005-12-22 00:43
2006.01.29
Узнать каким процессом занят фаил.


2-1137155643
Dark Lord
2006-01-13 15:34
2006.01.29
Ошибка при коннекте в NMPOP3


2-1136735763
АндрейЙ
2006-01-08 18:56
2006.01.29
Обращение к ячейкам DBGrid


15-1136220317
Zryndin
2006-01-02 19:45
2006.01.29
Коммерческие компоненты


1-1135417918
NailMan
2005-12-24 12:51
2006.01.29
Глюк Дельфи с записью строковой переменной