Background worker не улавя грешки от ThreadPool

Използвам BackgroundWorker, тъй като трябва да дам обратна връзка в моя потребителски интерфейс. Също така трябва да използвам ThreadPool в моя клас, за да работи асинхронно, но изглежда, че моят фонов работник не може да улови изключението, което хвърля.

Той има за цел да даде обратна връзка за задачата, която изпълнява.

Направих просто приложение, което възпроизвежда проблема:

    // MAIN UI CLASS

    BackgroundWorker _bgWorker = new BackgroundWorker();

    void _bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {

        if (e.Error != null)
        {
            // Returns custom error
            MessageBox.Show(e.Error.Message);
        }
    }

    void _bgWorker_DoWork(object sender, DoWorkEventArgs e)
    {
         try {
            // Initialize test error class
            var testClass = new TestClass();
         }
         catch (Exception ex)
         {
             MessageBox.Show("im from trycatch");
         }


    }
    private void Window_ContentRendered(object sender, EventArgs e)
    {
        _bgWorker.DoWork += _bgWorker_DoWork;
        _bgWorker.RunWorkerCompleted += _bgWorker_RunWorkerCompleted;
    }

    /////////////////////////////////////////////////////////////////////////

    // TEST ERROR CLASS
    public TestClass()
    {
        throw new Exception("im a custom error");
    }

Това работи добре. С try-catch той улавя грешката, както се обработва от try-catch. Докато, без try-catch, той го обработва в RunWorkerCompleted.

Наистина обаче трябва да правя тези методи асинхронно (поради което използвам ThreadPool), но дебъгерът винаги сочи към изключението. (само срива програмата, когато я пробвам без програмата за отстраняване на грешки)

    // TEST ERROR CLASS
    public TestClass()
    {
        ThreadPool.QueueUserWorkItem(delegate
        {
             throw new Exception("im a custom error");
        }
    }

Опитах се да върна грешката с помощта на оператор try-catch (надявайки се, че ще предаде изключението на BackgroundWorker), но не проработи.

Надявам се, че можете да ми помогнете. Благодаря предварително.


person CudoX    schedule 02.05.2014    source източник
comment
Защо напълно отделна нишка (може да) предаде изключение на Bgw?   -  person Henk Holterman    schedule 02.05.2014
comment
Просто използвайте (друг) Bgw или погледнете класовете Task и Parallel. Голите (пул)нишки не извършват препращане на изключения.   -  person Henk Holterman    schedule 02.05.2014
comment
Няколко мисли ... каква версия на .NET използвате? Ако използвате .NET 4 или по-рано, определено има по-добри начини да направите това. Преосмислете защо искате DoWork метод на фонов работник да постави нещо в ThreadPool. Казвате, че трябва да използвате нишковия пул за асинхронна работа, но това не е вярно, BackgroundWorker прави това вместо вас, но извиква вашия метод „DoWork“ в нишка на ThreadPool... msdn.microsoft.com/en-us/library/h01xszh2(v=vs.110).aspx. трябва само да извикате RunWorkerAsync, който не показвате в кода си. Това е смисълът на използването на BackgroundWorker.   -  person TCC    schedule 02.05.2014


Отговори (1)


Не е необходимо да поставяте код в ThreadPool от метода DoWork. BackgroundWorker автоматично ще повдигне вашия _bgWorker_DoWork метод в нишка на ThreadPool, когато извикате RunWorkerAsync().

Ако се опитвате да стартирате ОЩЕ НЯКОЛКО задачи на ThreadPool от вашия фонов работник, тогава предполагам, че това може да бъде съображение, но в такъв случай бих предложил да използвате TPL в .NET4, ако изобщо е възможно...

http://msdn.microsoft.com/en-us/library/dd460717%28v=vs.110%29.aspx

Ако не можете да използвате TPL, тогава трябва да обвиете своя ThreadPool код в TryCatch и да поставите Exception на някое място, което може да бъде достъпно извън този метод.

Например добавете internal static List<Exception> backgroundExceptions; член към вашия UI клас, фоновият работник добавя всички уловени изключения към този списък и след това трябва да проучите този списък, след като работата ви във фонов режим приключи, за да видите дали има налични изключения.

По същество това е, което TPL прави за вас ... като ви дава място да „наблюдавате“ изключения, които се случват във фоновата нишка, но все пак е ваша отговорност да търсите тези изключения или в свойството Task.Exception, или чрез извикване метод, който ще хвърли отново изключението вместо вас.

person TCC    schedule 02.05.2014