Как подавить ошибку thread.abort () в C #? - PullRequest
4 голосов
/ 04 июня 2009

Я показываю заставку в фоновом потоке, пока загружается моя программа. Как только он загружается, я прерываю поток, поскольку его единственной целью было показать всплывающую форму «Сейчас загружается».

Моя проблема в том, что при прерывании потока он выдает ThreadAbortException, что пользователь может просто нажать Продолжить.

Как мне с этим справиться? Я пытался подавить это так ->

            try
        {
            Program.splashThread.Abort();
        }
        catch(Exception ex)
        {

        }

но у меня такое чувство, что меня здесь орут, и это никак не работает.

Спасибо!

Ответы [ 8 ]

20 голосов
/ 04 июня 2009

Вам не нужно отменять тему. Я приведу пример с кодом.

В форме заставки:

public void CloseSplash()
{
    Invoke((MethodInvoker)delegate
    {
        this.Close();
    });
}

В файле Program.cs:

private static Splash _splash = null;
public static void CloseSplash()
{
    if (_splash!= null)
    {
        _splash.CloseSplash();
    }
}

Теперь, когда ваш метод Main запускается, покажите всплеск в потоке:

Thread t = new Thread(new ThreadStart(delegate
{
    _splash = new Splash();
    _splash.ShowDialog();
}));

t.Start();

... и когда вы хотите закрыть его, просто закройте его:

Program.CloseSplash();

Тогда вам не нужно беспокоиться о прерывании потока; он выйдет изящно.

9 голосов
/ 04 июня 2009

Пожалуйста, обратитесь к следующей ссылке, полученной при поиске в Google (возвращен первый результат):

http://msdn.microsoft.com/en-us/library/5b50fdsz.aspx

Обратите особое внимание на эту часть:

Когда этот метод вызывается в потоке, система выбрасывает ThreadAbortException в потоке, чтобы прервать его. ThreadAbortException - это особое исключение, которое может быть перехвачено кодом приложения, но повторно генерируется в конце блока catch, если не вызывается ResetAbort . ResetAbort отменяет запрос на отмену и запрещает ThreadAbortException завершить поток. Неисполненные блоки finally выполняются до прерывания потока.

7 голосов
/ 04 июня 2009

Использование Threadabort не рекомендуется. Это зло Почему бы не использовать другой механизм, такой как (Авто / Ручной) ResetEvent? Начните тему с заставки, дождитесь события. Если другой код завершил загрузку, установите событие en так, чтобы заставка закрывалась как обычно (приятно).

4 голосов
/ 04 июня 2009

Некоторые баллы. Исключение ThreadAbort является причиной прерывания потока. Это не побочный эффект того, что вы вызываете прерывание. Когда вы вызываете abort в потоке, среда выполнения заставляет исключение threadabort распространяться в потоке. Это исключение может быть перехвачено, поскольку оно позволяет пользователю выполнить некоторую очистку перед прерыванием потока.

Затем исключение автоматически перебрасывается, чтобы гарантировать, что поток прерван. Если исключение было перехвачено и оно не было переброшено, поток никогда не прервется.

Действительно интеллектуальный дизайн на самом деле.

Так что действительно нормально ловить это исключение. На самом деле вы должны. Но поймать только это конкретное исключение, а не общее исключение. (как показано ниже)

catch(ThreadAbortException ex)
{
   //This is an expected exception. The thread is being aborted
}
3 голосов
/ 04 июня 2009

Измените тип исключения на ThreadAbortException и добавьте вызов к ResetAbort ()

    try
    {
        Program.splashThread.Abort();
    }
    catch(ThreadAbortException ex)
    {
        Thread.ResetAbort();
    }

В общем, прерывание потоков считается очень плохой практикой и может привести к всевозможным трудным поискам ошибок. Вы не задумывались над тем, чтобы найти способ просто закрыть всплывающее окно или использовать какой-нибудь опрос , чтобы остановить поток, когда установлен флаг?

1 голос
/ 09 июля 2017

Попробуйте этот код. У меня все нормально работает.

void splash()
{
    try {
        SplashScreen.SplashForm frm = new SplashScreen.SplashForm();
        frm.AppName = "HR";

        Application.Run(frm);
    }
    catch (ThreadAbortException ex)
    {
        Thread.ResetAbort();
    }
}
1 голос
/ 04 июня 2009

Зачем ты это делаешь? Просто установите флаг, который поток опрашивает, и в конце концов, когда поток его подхватит, он закроется сам.

0 голосов
/ 23 июля 2009

Я использовал решение, предложенное Фредриком Мёрком. Это очень ясно и элегантно. В противном случае я обнаружил проблему, если мы создали экземпляр всплывающей формы перед запуском реального приложения (application.run (mainform ...)):

это вызывает исключение invalidOprationException, вызванное дескриптором формы, все еще не существующим в вызывающем потоке. Чтобы создать дескриптор непосредственно в потоке t (и пропустить это исключение!), Попробуйте запустить всплывающую форму следующим образом:

Thread t = new Thread(new ThreadStart(delegate
{
    _splash = new Splash();
     Application.Run(_splash);
}));

t.Start();

и, если вы планируете вызывать метод closeSplash в нескольких ветвях программы, принудительно установите нулевое значение после первого вызова:

    private static Splash _splash = null;
    public static void CloseSplash()
    {
        if (_splash!= null)
        {
            _splash.CloseSplash();
            _splash=null;
        }
}
...