Liberar Memória de Thread

Delphi

26/04/2008

Var
VThreadCaptions : TMinhaThread;
begin
VThreadCaptions := TMinhaThread.Create(True);
VThreadCaptions.Freeonterminate := true;
VThreadCaptions.Resume;

Com a rotina acima, cria-se uma variável de trhead e, ao término de sua execução, ela é destruída, certo?
Mas, e se o usuário interromper sua execução, o ´terminate´ não ocorreria e ela não seria destruída?
Num teste que fiz aqui, está ocorrendo um erro de memória quando interrompo a execução da trhead e chamo ela novamente. Se dou tempo dela terminar, o erro não ocorrem, ou seja, parece que, não ocorrendo o fim na rotina dentro da trhead, a memória não é liberada e quando ela vai ser executada pela segunda vez, ocorre o erro.

Alguém tem idéia de como resolver isso?

Obrigado.


Armindo

Armindo

Curtidas 0

Respostas

Rodc

Rodc

26/04/2008

Como você está fazendo a´pausa´ da thread? Com Pause ou Terminate?
Poste aqui o código demostrando a pausa e a retomada...
E coloque o código entre as tags ´CODE´ para não perder a formatação:
[code]
  código
[/code]


GOSTEI 0
Armindo

Armindo

26/04/2008

Como você está fazendo a´pausa´ da thread? Com Pause ou Terminate? Poste aqui o código demostrando a pausa e a retomada... E coloque o código entre as tags ´CODE´ para não perder a formatação:
[code]
  código
[/code]


Certo. Abaixo vai o código.
A trhead é executada no onActivate de cada form.
Quando o operador pressiona ESC em qualquer form, ele (o form) é fechado. Se o caption não sido todo ´escrito´ até o pressionamento do ESC, pois, como pode-se ver abaixo, ele é escrito letra por letra, ocorre uma interrupção na trhead e ela não ´terminate´, certo?

procedure TMinhaThread.execute;
Var
I : Integer;
VTexto : String;
begin
Sleep(300); //espero meio segundo para que o form seja totalmente mostrado na tela. Assim o efeito fica mais notável
Priority := tplower;
VTexto := VCaption; //Vcaption é uma variável da trhead e que recebe valor no onActivate do form
for I := 1 to Length(VTexto) do
begin
VForm.Caption := VForm.Caption + VTexto[I];
sleep(50);
end;
inherited;
end;

Por gentileza, veja se tens uma solução.
Obrigado


GOSTEI 0
Rodc

Rodc

26/04/2008

É preciso testar se a thread está sendo encerrada para sair do loop.
Veja como usando as Tags do CODE fica mais ´bonito´ e fácil de entender o código postado no forum:
procedure TMinhaThread.execute; 
Var 
  I : Integer; 
  VTexto : String; 
begin 
  Sleep(300); //espero meio segundo para que o form seja totalmente mostrado na tela. Assim o efeito fica mais notável 
  Priority := tplower; 
  VTexto := VCaption; //Vcaption é uma variável da trhead e que recebe valor no onActivate do form 
  for I := 1 to Length(VTexto) do 
  begin
    if Terminated then break; // Verifica se alguém solicitou o encerramento da Thread
    VForm.Caption := VForm.Caption + VTexto[I]; 
    sleep(50); 
  end; 
   inherited; 
end;



GOSTEI 0
Armindo

Armindo

26/04/2008

É preciso testar se a thread está sendo encerrada para sair do loop. Veja como usando as Tags do CODE fica mais ´bonito´ e fácil de entender o código postado no forum:
procedure TMinhaThread.execute; 
Var 
  I : Integer; 
  VTexto : String; 
begin 
  Sleep(300); //espero meio segundo para que o form seja totalmente mostrado na tela. Assim o efeito fica mais notável 
  Priority := tplower; 
  VTexto := VCaption; //Vcaption é uma variável da trhead e que recebe valor no onActivate do form 
  for I := 1 to Length(VTexto) do 
  begin
    if Terminated then break; // Verifica se alguém solicitou o encerramento da Thread
    VForm.Caption := VForm.Caption + VTexto[I]; 
    sleep(50); 
  end; 
   inherited; 
end;


Obrigado colega pela resposta.
O erro continua, mas não só ocorre se eu exectuar compilando.
Vou dar mais algumas pesquisadas. Se achar a solução, postarei aqui.

Obrigado.


GOSTEI 0
Massuda

Massuda

26/04/2008

Tire o [b:bfa6a652d5]inherited[/b:bfa6a652d5].... TThread.Execute é abstrata, por isso TMinhaThread.Execute não pode executar o método herdado.

Além disso... isso não poderia ser feito usando um TTimer?


GOSTEI 0
Rodc

Rodc

26/04/2008

Mas o inherited chega a causar algum problema ou ele simplemente desconsidera por se abstrato?

Armindo, sugiro também fazer a mudança do Caption através de uma função que seja chamada através do método Synchronize().


GOSTEI 0
Massuda

Massuda

26/04/2008

Mas o inherited chega a causar algum problema ou ele simplemente desconsidera por se abstrato?
Gera uma exceção EAbstractError.


GOSTEI 0
Armindo

Armindo

26/04/2008

Prezado Massuda,

Até dá prá fazer com timer, só que aí o form só ficaria liberado para o operador depois que a rotina terminasse. Num caption um pouco grande, isso demoria alguns segundos.

Mas por que você sugeriu o timer em substituição a thread? Só para que esse problema fosse solucionado ou emu sistema teria menos ´peso´ usando o timer?

Obrigado.


GOSTEI 0
Armindo

Armindo

26/04/2008

Tire o [b:bc5ad0be84]inherited[/b:bc5ad0be84].... TThread.Execute é abstrata, por isso TMinhaThread.Execute não pode executar o método herdado. Além disso... isso não poderia ser feito usando um TTimer?


Tirei, mas não resolveu.


GOSTEI 0
Massuda

Massuda

26/04/2008

Até dá prá fazer com timer, só que aí o form só ficaria liberado para o operador depois que a rotina terminasse.
Não vejo como isso possa ocorrer. Independente da execução do timer, o usuário pode fechar o form a qualquer instante.

Num caption um pouco grande, isso demoria alguns segundos.
Com thread também. Qual a vantagem da thread então?

Mas por que você sugeriu o timer em substituição a thread?
Porque me parece muito complicado para uma coisa simples e, sim, thread vai consumir mais recursos da máquina (mais ´pesado´).


GOSTEI 0
Armindo

Armindo

26/04/2008

[quote:cfbe2af345=´Armindo´]Até dá prá fazer com timer, só que aí o form só ficaria liberado para o operador depois que a rotina terminasse.
Não vejo como isso possa ocorrer. Independente da execução do timer, o usuário pode fechar o form a qualquer instante.

Num caption um pouco grande, isso demoria alguns segundos.
Com thread também. Qual a vantagem da thread então?

Mas por que você sugeriu o timer em substituição a thread?
Porque me parece muito complicado para uma coisa simples e, sim, thread vai consumir mais recursos da máquina (mais ´pesado´).[/quote:cfbe2af345]

Vamos supor que tenha um timer (timer1) na aplicação e eu coloque uma determinada rotina no evento onTimer desse timer. Essa aplicação tem um botão que executa uma rotina qualquer quando clicado. No onActivate de um form dessa aplicação, eu coloco timer1.enabled := true.
Até onde eu sei e testei, no exemplo acima, o botão do form só estará disponível para ser clicado quando toda rotina do timer tiver sido executada.
Numa mesma aplicação, só que com a rotina sendo sendo executada por uma thread em vez do timer, o botão ficará disponível assim que o form for carregado. Essa é a vantagem.
Estou errado?


GOSTEI 0
Rodc

Rodc

26/04/2008

Ele só fica travado quando a rotina do timer for executada. Por exemplo, se você pôs para atualizar o Caption a cada 1 segundo, apenas a cada 1 segundo ele vai processar a rotina que atualiza o Caption e enquanto não estiver processando a atualização do Caption a aplicação está liberada para você clicar no botão ou em qualquer outro componente.


GOSTEI 0
Armindo

Armindo

26/04/2008

Vejam um teste que fiz.

procedure TMinhaThread.execute;
Var
I : Integer;
VTexto : String;
begin
Sleep(300); //espero meio segundo para que o form seja totalmente mostrado na tela. Assim o efeito fica mais notável
Priority := tplower;
VTexto := VCaption; //Vcaption é uma variável da trhead e que recebe valor no onActivate do form
for I := 1 to Length(VTexto) do
begin
VForm.Caption := VForm.Caption + VTexto[I];
if I = 5 then Self.Close; [b:4f78d9fd4a]este é o teste adicional[/b:4f78d9fd4a]
sleep(50);
end;
inherited;
end;

Nesse teste, na quinta volta ocorre o erro, pois o form está sendo fechado sem que a trhead tenha terminado.
Repito: o problema só ocorre quando executo o programa compilando no Delphi. Se rodar o aplicativo normal (fora do Delphi), não acontece nenhum erro.


GOSTEI 0
Massuda

Massuda

26/04/2008

Pelo que entendi, é isto que você quer...
type
  TSeuForm = class(TForm)
    ...
    SeuTimer: TTimer;
  private
    FTitulo: string;
    FPosicao: Integer;
    ....


procedure TSeuForm.SeuFormCreate(Sender: TObject);
begin
  FTitulo := ´Um titulo qualquer´;
  FPosicao := 0;
  Caption := ´´;
  ...
end;

procedure TSeuForm.SeuFormActivate(Sender: TObject);
begin
  SeuTimer.Enabled := True;
  ...
end;

procedure TSeuForm.SeuFormDeactivate(Sender: TObject);
begin
  SeuTimer.Enabled := False;
  ...
end;

procedure TSeuForm.SeuTimerTimer(Sender: TObject);
begin
  Inc(FPosicao);
  Caption := Caption + FTitulo[FPosicao];

  SeuTimer.Enabled := FPosicao < Length(FTitulo);
end;


Notei que você usa um intervalo de 50ms entre cada letra... isso dá 20 letras por segundo... o efeito visual fica bom? Acho que muitas pessoas nem perceberão o efeito.


GOSTEI 0
Armindo

Armindo

26/04/2008

Descobri o problema.

O que acontecia era o seguinte: eu mandava o form que receberia o caption como uma variável (VForm). A thread era iniciada e rodava o loop até que todas as letras da variável VCaption, também enviada no chamamento da rotina, fosse escritas. Se, no meio da execução da thread o form fosse fechado, a thread continuaria sendo executada, mas o form já não existiria e isso geraria o erro, pois no onClose, o form é destruído.
Testei seu código Massuda, e realmente funciona com timer. Agora ambas as opções funcionam legal, hehe!
Acho que vou deixar a rotina que utiliza o timer, pois se exige menos da máquina..., é sempre melhor poupar né?.

Obrigado a todos que colaboraram!


GOSTEI 0
POSTAR