Qual é a melhor maneira de determinar que os threads pararam?
-
26-09-2019 - |
Pergunta
Eu tenho um serviço do Windows que possui vários threads que precisam ser interrompidos antes da parada do serviço. Estou usando este modelo para interromper meus tópicos e sinalizar que eles foram interrompidos:
ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
{
Thread1Running = true;
try
{
while (running)
{
AutoReset1.WaitOne(TimeSpan.FromSeconds(30.0));
if (running)
{
// do stuff
}
}
}
finally
{
Thread1Running = false;
}
}));
Quando chega a hora de fechar meu serviço para parar, basta definir o Running para False e Call Set () em todos os Autoresets por aí. Isso indica instantaneamente os threads para parar de dormir ou para parar quando terminarem de processar o que estão trabalhando. Isso funciona muito bem. Mas, a parte que estou mais nervosa é verificar que tudo parou. Isso é o que estou fazendo agora:
Int32 tries = 0;
while (tries < 5 && (Thread1Running || Thread2Running || Thread3Running))
{
tries++;
Thread.Sleep(TimeSpan.FromSeconds(5.0));
}
A principal razão pela qual eu não gosto disso é que é baseado no tempo, e se um dos meus tópicos estiver no meio de uma longa operação (o que é bem provável), o desligamento pode não terminar nesses 25 segundos (e é Muito importante que todos esses threads sejam desligados quando no momento, onde esse código é executado, termina). Não posso remover as tentativas, porque se um desses threads está pendurado (eles não, mas você nunca sabe), então estou realmente preso e o serviço nunca vai parar.
Existe uma maneira melhor de fazer a verificação que todos os threads pararam, de preferência um que não seja baseado no tempo? Ou estou fadado a ter algum tipo de tempo limite que possa precisar ser muito mais longo (10 tentativas com um sono de 30 segundos, talvez)?
Solução
Acredito que o método geral para fazer isso é entrar nos tópicos. As especificidades da chamada dependerão da biblioteca de encadeamento que você está usando, mas em geral o join
O método bloqueará até que o encadeamento tenha saído (e retorne imediatamente se o thread já estiver morto). Então, você pode simplesmente participar de todos os seus tópicos em sequência e depois sair. Se todas as suas junções retornaram, todos os threads saíram.
Muitas bibliotecas de encadeamento permitem que você adicione um tempo limite para participar, o que você provavelmente gostaria de fazer. Dessa forma, mesmo que um de seus threads pendure seu código de saída não bloqueie.