Como faço para suprimir um thread.abort () erro c#?
-
11-09-2019 - |
Pergunta
Estou mostrando uma tela de respingo em um tópico de segundo plano enquanto meu programa carrega. Depois de carregar, estou abortando o fio, pois o único objetivo era mostrar uma forma de respingo de carregamento agora.
Meu problema é que, ao abortar um fio, joga um ThreadAbortException
que o usuário pode simplesmente clicar em continuar.
Como faço para lidar com isso? Eu estava tentando suprimir assim ->
try
{
Program.splashThread.Abort();
}
catch(Exception ex)
{
}
Mas tenho a sensação de que vai me fazer gritar aqui e não funciona de forma alguma.
Obrigado!
Solução
Você não precisa cancelar o tópico. Vou exemplificar com o código.
No formulário de tela Splash:
public void CloseSplash()
{
Invoke((MethodInvoker)delegate
{
this.Close();
});
}
No arquivo program.cs:
private static Splash _splash = null;
public static void CloseSplash()
{
if (_splash!= null)
{
_splash.CloseSplash();
}
}
Agora, quando seu método principal começar, mostre o respingo em um tópico:
Thread t = new Thread(new ThreadStart(delegate
{
_splash = new Splash();
_splash.ShowDialog();
}));
t.Start();
... e quando você quiser fechar, basta fechar:
Program.CloseSplash();
Então você não precisa se preocupar em abortar o fio; Vai sair graciosamente.
Outras dicas
Consulte o link a seguir obtido fazendo uma pesquisa no Google (primeiro resultado retornado):
http://msdn.microsoft.com/en-us/library/5b50fdsz.aspx
Preste atenção especial a esta parte:
Quando esse método é chamado em um fio, o sistema lança um ThreadAborTexception no tópico para abortá -lo. ThreadAborTexception é uma exceção especial que pode ser capturada pelo código do aplicativo, mas é renovado no final do bloco de captura, a menos que Resetabort é chamado. Resetabort cancela o pedido de abortar e impede o ThreadAborTexception de encerrar o thread. Os blocos finalmente não executados são executados antes que o tópico seja abortado.
Usando Threadabort não é recomendado. É mau. Por que não usar outro mecanismo como um retevent (automático/manual)? Inicie o tópico com a tela de respingo, aguarde o evento. Se o outro código for feito carregando coisas, defina o evento em permitir que a tela de respingo feche a maneira normal (agradável).
Alguns pontos. A exceção do Threadabort é a razão pela qual o fio aborta. Não é um efeito colateral de você chamar o aborto. Quando você liga para abortar em um thread, o tempo de execução força uma exceção do Threadabort a ser propagada ao thread. Essa exceção pode ser capturada porque permite ao usuário executar alguma limpeza antes que o thread aborte.
A exceção é repensada automaticamente para garantir que o thread seja abortado. Se a exceção fosse capturada e se não fosse repensar, o fio nunca abortaria.
Design realmente inteligente, na verdade.
Portanto, não há problema em pegar essa exceção. Na verdade, você deveria. Mas pegue apenas essa exceção específica e não a exceção geral. (como mostrado abaixo)
catch(ThreadAbortException ex)
{
//This is an expected exception. The thread is being aborted
}
Alterar o tipo de exceção para ThreadAborTexception e adicione uma chamada para Resetabort ()
try
{
Program.splashThread.Abort();
}
catch(ThreadAbortException ex)
{
Thread.ResetAbort();
}
Em geral, os threads abortados são considerados práticas muito ruins e podem levar a todos os tipos de bugs difíceis de rastrear. Você já pensou em descobrir uma maneira de apenas Feche a janela do Splash ou use algum tipo de votação Para parar o tópico quando uma bandeira foi definida?
Por que você faria isso? Basta definir uma bandeira que as pesquisas de encadeamento e, eventualmente, quando o thread o pegar, ele se fechará.
Experimente este código. Está funcionando bem para mim.
void splash()
{
try {
SplashScreen.SplashForm frm = new SplashScreen.SplashForm();
frm.AppName = "HR";
Application.Run(frm);
}
catch (ThreadAbortException ex)
{
Thread.ResetAbort();
}
}
Eu usei a solução sugerida por Fredrik Mörk. É muito claro e elegante. Caso contrário, encontrei um problema se instanciarmos o formulário Splash antes de lançar o aplicativo real (Application.run (Mainform ...)):
Ele levanta uma concepção de invalidoPration causada pela manutenção de formulários ainda não existe no thread de chamadas. Para criar o identificador diretamente no thread t (e pule esta exceção!), Tente iniciar a forma de respingo dessa maneira:
Thread t = new Thread(new ThreadStart(delegate
{
_splash = new Splash();
Application.Run(_splash);
}));
t.Start();
E, se você planeja chamar o método Closesplash em mais ramos do programa, force o valor nulo após a primeira chamada:
private static Splash _splash = null;
public static void CloseSplash()
{
if (_splash!= null)
{
_splash.CloseSplash();
_splash=null;
}
}