Форум: "Основная";
Текущий архив: 2006.01.29;
Скачать: [xml.tar.bz2];
ВнизПроблема в многопоточном приложении: завершение потоков. Найти похожие ветки
← →
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;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.034 c