kończenie wątku i usunięcie jego składowych

0

Witam,
mam wątek:

  tTwatek = class(TThread)
    protected
      czas : Real;
      obraz : TImage;
      procedure Execute; override;
      procedure odswiez;
  end;

Przy kazdym odswiezaniu zmienna "czas" zwiększa się o jeden. Chciałbym, aby po pewnym czasie wątek się sam zakończył.

Niby proste - odpowiedni warunek w Execute

 procedure tTWatek.Execute;
  begin
    FreeOnTerminate := True;
    while not Terminated do
    begin
      if czas>5 then
      begin
        TerminateThread(Handle,0);
        obraz.Free;
//        Form1.Button3.Click;
      end;
      Synchronize(odswiez);
      Sleep(1000);
    end;
  end;

Niestety wątek się kończy, ale obrazek nie znika... Czy ktos to może wyjaśnić..?
Myslałem, że FreeOnTerminate załatwi wszystko, ale jednak nie.

Co ciekawe - dodałem przycisk i pod nim procedurę

procedure TForm1.Button3Click(Sender: TObject);
begin
  TerminateThread(watek.Handle,0);
  watek.obraz.Free;
end;

I to działa!!! - wątek się kończy i obraz znika, ale... musze sam kliknąć...
Jak widac próbowałem automatycznie wywołac kliknięcie tego przycisku, ale standardowo - wątek sie kończy, a obraz zostaje... :(

Byłbym wdzięczny za jakies wskazówki...

0

W pierwszym przykładzie zwolnienie obrazu ma być wykonane przez wątek po przerwaniu watku. Jakby więc ma zadziałać?

W przykładzie drugim procedura watek.obraz.Free jest wykonywana przez głowny watek procesu, więc zadziała nawet jesli wątek nie istnieje.

Dlaczego nie:

   if czas>5 then
     begin
        obraz.Free;
        TerminateThread(Handle,0);
      end;
0

Z wątkami jak z dziećmi, jeśli dasz mu suspend albo termiante zastosuje się do tego i przestanie wykonywać następne polecenia, dlatego jeśli nie masz w execute standardowej wersji while not terminate to musisz uwazać na liczbę linijek.
Druga sprawa ze zwalniając pamięć po wątku poprzez free nie zwalniasz kaskadowo, więc jeśli maiłem jakieś inne obiekty podpięte pod watek to musisz najpierw je pozwalniać.

0

Też mi się wydawało, że najpierw trzeba zwolnić pamięć po obrazku, a dopiero potem zamknąć wątek i tak początkowo zrobiłem... Niestety to nie działa... Pojawia się wtedy błąd "Access violation at address 77F51BAA in module 'ntdll.dll'. Write of address 00000010". Sprawdzałem to też BC++Builder i tam jest dokładnie to samo...

0

Widzę, że nie dowiem się chyba jednak jak to rozwiązać..
Może to pomoże

procedure tTWatek.Execute;
  begin
    FreeOnTerminate := True;
    while not Terminated do
    begin
      Synchronize(odswiez);
      if czas>5 then
      begin
        obraz.Free;
        Terminate;
      end;
      Sleep(1000);
    end;
  end;

Czyli poprawiłem nieco kod i (w sumie oczywiste... ;) ) przesunałem usunięcie obrazka "obraz" ponizej wywolania Synchronize(odswiez) i teraz czasami obrazek znika bezboleśnie, ale czasami nadal się pojawia ten błąd "Access violation..."...
Może to kogoś naprowadzi na rozwiązanie

0

to może pokaż jak tworzysz obraz?

0

zanim zwolnisz obiekt obraz, sprawdź czy naprawdę siedzi w nim obiekt -> zamiast Free daj FreeAndNil, a przed FreeAndNil daj if obraz <> nil then albo if assigned(obraz) then.

przy okazji - zamiast terminate prościej jest po prostu wyjść z wątku poprzez exit;

0

Obrazek tworzę w następujący sposób:

procedure TForm1.FormCreate(Sender: TObject);
begin
  watek := tTWatek.Create(False);
  watek.obraz := TImage.Create(Form1);
  watek.obraz.Parent := Form1;
  watek.obraz.Left := 10;
  watek.obraz.Top := 10;
  watek.obraz.Picture.LoadFromFile('kulka.ico');
  watek.czas := 0;
end;

Niestety poprawka

 if obraz <> nil then
   obraz.free;

ani

  if obraz <> nil then
    freeandnil(obraz);

nic sie nie zmienia. Ciągle komunikat "Access violation..."

Co do wyjścia z wątku, to terminte działa, więc nie będę chyba zmieniał...

Ktoś mi powiedział, że ten komunikat oznacza, że próbuję się odwołać do czegoś co nie istnieje, dlatego myslałem, że wskazówka ŁF'a (ŁF'y) pomogą, ale jednak nie o to chodzi, więc temat nadal otwarty...

0

zamiast
watek.obraz := TImage.Create(Form1);
daj
watek.obraz := TImage.Create(nil);

0

Zastosowałem (z pewnym niedowierzaniem..) sposób Misiekd'a, ale nie pomogło. Obrazek pojawił się i przy znikaniu wyskoczył standardowy błąd...

Słuchajcie :-/
Pomyślałem sobie, że skoro to taki problem, to zamiast kasowania obrazka może wczytam nowy pusty... Tylko mam pytanie, co się wtedy dzieje w pamięci kompa..? Pamięć po obrazku nie zostanie zatem zwolniona, a dodatkowo załaduję nowy obrazek (ikonke). Ikonka zajmuje 766 bajtów i gdybym miał (np. w jakiejs gierce) 1000 takich watkow to byłoby to już ładne 766 kilo bajtow... Co Wy na to?

0

Błąd pojawia się rzeczywiście z powodu odwoływania się do obiektu, który nie istnieje. Jeśli masz więcej wątków, które odwołują się do tego samego obrazka lub odwołujesz się do niego z zewnątrz, to masz już przyczynę problemu. Pomysł by zamiast

watek.Terminate

dać exit

 i przez to wyjść z pętli <code class="delphi">while

, więc i zakończyć procedurę execute

, co pociąga za sobą zniszczenie wątku, jest jak najbardziej dobry!
0

dodaj nową metodę dla wątku

procedure tTWatek.FreeImage;
begin
  FreeAndNil(obraz);
end;

a w wątku zamiast

obraz.Free;

daj

Synhronize(FreeImage);
0

Dzięki za szybką odpowiedź. Jak będe miał chwilę (pewnie w weekend) to na pewno to sprawdzę. Trza się spieszyć, bo już niedługo zaliczenie tego programu... :(
Pozdrawiam

0

Co mogę powiedzieć... Działa [!!!] [!!!] [browar]
Pomogła Twoja ostatnia wskazówka Misiekd

Zrobiłem dokładnie tak jak napisałeś

 procedure tTWatek.Execute;
  begin
    FreeOnTerminate := True;
    while not Terminated do
    begin
      Synchronize(odswiez);
      if czas>5 then
      begin
        Terminate;
        Synchronize(FreeImage);
      end;
      Sleep(1000);
    end;
  end;

Wielkie dzieki, bo do konca tygodnia muszę mieć napisany ten program ;)

P.S.
Nawiasem mówiąc, to wypróbowałem to w BC++Builder i tam też był ten sam problem i też pomogło

 
Synchronize(FreeImage) 

ALE musiałem w procedurze dać nie

 FreeAndNil(obraz);

tylko

delete obraz;

bo inaczej nie działało...

Pozdrawiam i do następnego pytania

1 użytkowników online, w tym zalogowanych: 0, gości: 1