Catch exceptions in another thread?

When developing winform applications, it is usually just necessary to invoke the main GUI thread to work with the graphical interface.

Invokeoutdated today (if I read correctly), you should use instead SynchronizationContext.

Question: How to handle exceptions? I noticed that sometimes the exception thrown from the "synced / invoked" thread gets lost?

I use Application.ThreadExceptionand AppDomain.CurrentDomain.UnhandledException, but it does not help?

+3
source share
2 answers

, - , .NET 2.0. . Control.Invoke . WinFormsSynchronizationContext, WinForms, Control.BeginInvoke Post Control.Invoke Send.

? , "synced/invoked" ?

"" "". Control.Invoke - , :

int Test()
{
    throw new InvalidOperationException("Surpise from the UI thread!");
}

void Form_Load(object sender, EventArgs e)
{
    // UI thread
    ThreadPool.QueueUserWorkItem(x =>
    {
        // pool thread
        try
        {
            this.Invoke((MethodInvoker)Test);
        }
        catch (Exception ex)
        {
            Debug.Print(ex.Message);
        }
    });
}

SynchronizationContext WinForms. , WinForms, WPF, Windows Phone, Xamarin :

// UI thread
var uiSynchronizationContext = System.Threading.SynchronizationContext.Current;
if (uiSynchronizationContext == null)
    throw new NullReferenceException("SynchronizationContext.Current");

ThreadPool.QueueUserWorkItem(x =>
{
    // pool thread
    try
    {
        uiSynchronizationContext.Send(s => Test(), null);
    }
    catch (Exception ex)
    {
        Debug.Print(ex.ToString());
    }
});

, Control.Invoke ( SynchronizationContext.Send) . Control.BeginInvoke ( SynchronizationContext.Post), . , Control.BeginInvoke , , , Application.Run.

, , . # 5.0 Task.ContinueWith.

:

class ErrorEventArgs : EventArgs
{
    public Exception Exception { get; set; }
}

event EventHandler<ErrorEventArgs> Error = delegate { };

void Form_Load(object sender, EventArgs e)
{
    this.Error += (sError, eError) =>
        // handle the error on the UI thread
        Debug.Print(eError.Exception.ToString()); 

    ThreadPool.QueueUserWorkItem(x =>
    {
        this.BeginInvoke(new MethodInvoker(() => 
        {
            try
            {
                Test();
            }
            catch (Exception ex)
            {
                // fire the Error event
                this.Error(this, new ErrorEventArgs { Exception = ex });
            }
        }));
    });
}

ContinueWith:

ThreadPool.QueueUserWorkItem(x =>
{
    var tcs = new TaskCompletionSource<int>();

    uiSynchronizationContext.Post(s => 
    {
        try
        {
            tcs.SetResult(Test());
        }
        catch (Exception ex)
        {
            tcs.SetException(ex);
        }
    }, null);

    // observe the completion,
    // only if there an error
    tcs.Task.ContinueWith(task =>
    {
        // handle the error on a pool thread
        Debug.Print(task.Exception.ToString());
    }, TaskContinuationOptions.OnlyOnFaulted);

});

, # 5.0, async/await , , try/catch, :

int Test()
{
    throw new InvalidOperationException("Surpise from the UI thread!");
}

async void Form_Load(object sender, EventArgs e)
{
    // UI thread
    var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    await Task.Run(async () =>
    {
        // pool thread
        try
        {
            await Task.Factory.StartNew(
                () => Test(), 
                CancellationToken.None,
                TaskCreationOptions.None,
                uiTaskScheduler);
        }
        catch (Exception ex)
        {
            // handle the error on a pool thread
            Debug.Print(ex.ToString());
        }
    });
}
+6

ui, .

1) , , HandleExceptionFromThread (Exception ex);

2) SynchronizationContext ui. , SynchronizationContext.Current.

3) , , SynchronizationContext . , SyncrhonizationContact, .

4) , uiContext.Send(HandleExceptionFromThead, ex), , uiContext.Post(HandleExceptionFromThead, ex) , , .

, .

public partial class Form1 : Form
{
    .....
    public void HandleExceptionFromThread(Exception ex)
    {
        MessageBox.Show(ex.Message);
    }

    public void ButtonClickToRunThread(object sender, System.EventArgs e)
    {
        var syncContext = SynchronizationContext.Current;
        Task task = new Task((state)=>
        {
            SynchronizationContext uiContext = state as SynchronizationContext;
            try
            {
                ...
            }
            catch(Exception ex)
            {
                uiContext.Post(HandleExceptionFromThread, ex);
            }
        }, syncContext);
        task.Start();
    }
}
0

All Articles