Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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.04 c
6-1129727738
Sergey840
2005-10-19 17:15
2006.01.29
IdHTTP (Загрузка страницы с 404 ошибкой)


2-1136799965
St74
2006-01-09 12:46
2006.01.29
Хеширование по алг MD5?


15-1135924999
syte_ser78
2005-12-30 09:43
2006.01.29
стоит ли менять?


15-1135842060
Ega23
2005-12-29 10:41
2006.01.29
Предчуствия.


15-1136561056
Барлог(с)
2006-01-06 18:24
2006.01.29
Чат в локальной сети. Какой поставить?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский