Delphi - encerrar todos os fios (TThread) sobre o pedido de fechamento
Pergunta
Meu aplicativo é um servidor TCP / IP, com thread principal criado apenas uma vez e ouvindo o tempo todo. Quando um novo cliente se conecta, o thread principal cria o novo segmento do tipo TClientThread
. Contudo, não há lista de execução tópicos cliente, como que faria meu aplicativo um pouco complicado ... existe alguma maneira de executar "terminar" método em todos os segmentos, mesmo se o segmento está ocupado (no meu caso "ocupado" meios que está esperando os dados, onde o conjunto de tempo limite é cerca de 30 segundos ... então eu tenho que matá-lo de qualquer maneira, sem esperar.)?
A aplicação simples de encerramento parece não correr "terminar" método sobre os tópicos, o que acaba com vazamentos de memória relatado por FastMM ...
Solução
Os vazamentos de memória no desligamento não são nada com que se preocupar - ir para a dificuldade de liberação de memória antes de retornar controle para o sistema operacional é um desperdício de tempo e atrasa inutilmente saída do aplicativo. Tudo que você realmente precisa fazer é garantir que todos os dados foram salvos, e todos os identificadores entre processos (tais como semáforos e semáforos) lançado corretamente, e sair de distância.
Para notificar os clientes, o melhor que você pode fazer seria uma estratégia mais ou menos assim:
- Adicione os tópicos de tratamento de cliente para alguns lista em algum lugar (com bloqueio adequado na criação, destruição e iteração)
- Faça threads cliente retirar-se da lista após a rescisão, e ter o último item removido da lista definir um evento (evento reset manual, por exemplo
TEvent
em SyncObjs) se o servidor está sendo desligado - Apresente polling (por exemplo
select
ou equivalente com um tempo limite) ou outro tipo de interrupção (por exemplo SO_RCVTIMEO / SO_SNDTIMEO) no que de outra forma seriam longa rotinas de bloqueio, monitorando a propriedade Terminado - No encerramento, bloquear a lista e iterate através dele, chamando
Terminate
, e depois esperar para o evento a ser sinalizado; é claro, o socket de escuta que acrescenta itens à lista deve ser fechado e conhecido por ser fechado antes de a iteração através da lista ??li>
Outras dicas
soa como este artigo pode ajudar
O que você vai ver se você clicar nesse link:
Usando semáforos em Delphi, Parte 2: O pool de conexão
Por: Cary Jensen
Abstract: Semáforos são usados ??para coordenar vários segmentos e processos. Que os semáforos fornecem vários segmentos com simultânea acesso a um recurso compartilhado é com destaque para o classe TFixedConnectionPool descrito neste artigo.
Eu uso um KillThreadList: TList global. I monitorá-lo na minha lista de discussão como:
while (Not Terminated) do
begin
inc(Inker);
if (WaitForSingleObject(FTick, finterval) = WAIT_TIMEOUT) then
Begin
if Inker >= 10 then
Begin
ProcessTables;
Inker := 0;
sleep(1000);
End;
if KillThreadList.Contains(ThreadID) = True then Terminate;
End;
end;
Eu também teste para a KillThreadList nos meus processos para deixar-me optar por sair de-los antes da conclusão, onde seguro fazê-lo.
I passar o evento OnTerminate para o segmento principal e retire a ThreadID do KillList lá. Eu uso este modelo extensivamente e não me falhou ainda.
procedure TfrmProcessQualcommLocations.OnTerminateThread;
var
ThreadID : Cardinal;
i : integer;
aStatusBar :TStatFrame;
begin
ThreadID := (Sender as Tthread).ThreadID;
for i := 0 to StatusBarList.Count -1 do
Begin
if StatusBarList.Items[i].ThreadID = ThreadID then
Begin
aStatusBar := StatusBarList.Items[i];
KillThreadList.Extract(ThreadID);
StatusBarList.Extract(aStatusBar);
aStatusBar.Free;
break;
End;
End;
self.Refresh;
end;
No caso acima, também estou removendo algumas coisas GUI.
Espero que ajude. SpringerRider