catching exceptions from another thread - c#

I have a method running in a seperate thread. The thread is created and started from a form in a windows application. If an exception is thrown from inside the thread, what is the best way to pass it back to the main application. Right now, I'm passing a reference to the main form into the thread, then invoking the method from the thread, and causing the method to be called by the main application thread. Is there a best practice way to do this because I'm not comfortable with how I'm doing it now.
Example of my form:
public class frmMyForm : System.Windows.Forms.Form
{
/// <summary>
/// Create a thread
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnTest_Click(object sender, EventArgs e)
{
try
{
//Create and start the thread
ThreadExample pThreadExample = new ThreadExample(this);
pThreadExample.Start();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Application.ProductName);
}
}
/// <summary>
/// Called from inside the thread
/// </summary>
/// <param name="ex"></param>
public void HandleError(Exception ex)
{
//Invoke a method in the GUI's main thread
this.Invoke(new ThreadExample.delThreadSafeTriggerScript(HandleError), new Object[] { ex });
}
private void __HandleError(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Example of my thread class:
public class ThreadExample
{
public delegate void delThreadSafeHandleException(System.Exception ex);
private Thread thExample_m;
frmMyForm pForm_m;
private frmMyForm Form
{
get
{
return pForm_m;
}
}
public ThreadExample(frmMyForm pForm)
{
pForm_m = pForm;
thExample_m = new Thread(new ThreadStart(Main));
thExample_m.Name = "Example Thread";
}
public void Start()
{
thExample_m.Start();
}
private void Main()
{
try
{
throw new Exception("Test");
}
catch (Exception ex)
{
Form.HandleException(ex);
}
}
}

So you're using Invoke to marshall back to the UI thread, by the looks of it - which is exactly what you need to do. I'd personally use an Action<Exception> for simplicity's sake, and possibly BeginInvoke instead of Invoke, but basically you're doing the right thing.

Use the BackgroundWorker class in the .NET framework instead. It is the best practice for performing UI work on a different thread.

Probably a better way would be to pass a delegate into the thread instead of a reference to the form itself.

Throwing exceptions between threads is not easy and probably not desired. instead you can pass the exception using a shared data structure or variable and use waitHandle to wait on the 1st thread.

I totally agree with Dror. In a formal way we can call this structure as FaultContract. Fundamentally when an exception has happened in another thread, the client thread can hardly do any thing at that moment except that to collect that information and act accordingly in it's own theread. If the thereads are in different AppPool then there is an extra complexity of Serialization (that can be a seperate topic altogether).

Related

set clipboard in async method

[STAThread]
static void Main(string[] args)
{
DoThing().Wait();
}
static async Task DoThing()
{
Clipboard.SetText("hi");
}
I added [STAThread] in the first place bc I got this error
ThreadStateException: Current thread must be set to single thread apartment (STA) mode before OLE calls can be made
But I am still getting the same error.
Clipboard is from System.Windows.Forms.
How do I set the clipboard from that async method?
The issue is that async threads are run from the threadpool, and they are all MTA threads. Task.Run() also creates MTA threads.
You will have to explicitly start an STA thread to run the code. Here's a sample helper class:
public static class STATask
{
/// <summary>
/// Similar to Task.Run(), except this creates a task that runs on a thread
/// in an STA apartment rather than Task's MTA apartment.
/// </summary>
/// <typeparam name="TResult">The return type of the task.</typeparam>
/// <param name="function">The work to execute asynchronously.</param>
/// <returns>A task object that represents the work queued to execute on an STA thread.</returns>
public static Task<TResult> Run<TResult>([NotNull] Func<TResult> function)
{
var tcs = new TaskCompletionSource<TResult>();
var thread = new Thread(() =>
{
try
{
// Most usages will require a message pump, which can be
// started by calling Application.Run() at an appropriate point.
tcs.SetResult(function());
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
/// <summary>
/// Similar to Task.Run(), except this creates a task that runs on a thread
/// in an STA apartment rather than Task's MTA apartment.
/// </summary>
/// <param name="action">The work to execute asynchronously.</param>
/// <returns>A task object that represents the work queued to execute on an STA thread.</returns>
public static Task Run([NotNull] Action action)
{
var tcs = new TaskCompletionSource<object>(); // Return type is irrelevant for an Action.
var thread = new Thread(() =>
{
try
{
action();
tcs.SetResult(null); // Irrelevant.
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
}
You could then implement DoThing() like this:
static async Task DoThing()
{
await STATask.Run(() => Clipboard.SetText("hi"));
}
Note that, as pointed out by Stephen Cleary, usually you need a message pump for an STA thread. You seem to be able to get away with this if you're just setting the clipboard text, but for anything more complicated you're likely to have to run a message pump in the thread.
The easiest way to run the message pump is via a call to Application.Run(), but you will have to handle the application context yourself.

Why is Task.Delay breaking the STA state of the thread?

Introduction
This is a lengthy question! You will find some background on the problem at the beginning, then code samples, which have been simplified for representation and the Question after that. Please read in any order that you find good for you!
Background information
I am writing a Proof-of-Concept part for an application for communicating with an STA COM. This part of the application has the requirement of running in a Single-Threaded Apartment (STA) context in order to communicate with said STA COM. The rest of the application runs in a MTA context.
Current state
What I have come up with so far is creating a Communication class that contains a while loop, running in a STA. The work that needs to be relayed to the COM object is queued from the outside to the Communication class via ConcurrentQueue. The work items are then dequeued in the while loop and the work is performed.
Code context
Communication class
This is a static class, containing a loop that is intended to run in STA state and check if some work needs to be done by the COM and dispatch the work to the handler.
static class Communication
{
#region Public Events
/// This event is raised when the COM object has been initialized
public static event EventHandler OnCOMInitialized;
#endregion Public Events
#region Private Members
/// Stores a reference to the COM object
private static COMType s_comObject;
/// Used to queue work that needs to be done by the COM object
private static ConcurrentQueue<WorkUnit> s_workQueue;
#endregion Private Members
#region Private Methods
/// Initializes the COM object
private static void InternalInitializeCOM()
{
s_comObject = new COMType();
if (s_comObject.Init())
{
OnCOMInitialized?.Invoke(null, EventArgs.Empty);
}
}
/// Dispatches the work unit to the correct handler
private static void HandleWork(WorkUnit work)
{
switch (work.Command)
{
case WorkCommand.Initialize:
InternalInitializeCOM();
break;
default:
break;
}
}
#endregion Private Methods
#region Public Methods
/// Starts the processing loop
public static void StartCommunication()
{
s_workQueue = new ConcurrentQueue<WorkUnit>();
while (true)
{
if (s_workQueue.TryDequeue(out var workUnit))
{
HandleWork(workUnit);
}
// [Place for a delaying logic]
}
}
/// Wraps the work unit creation for the task of Initializing the COM
public static void InitializeCOM()
{
var workUnit = new WorkUnit(
command: WorkCommand.Initialize,
arguments: null
);
s_workQueue.Enqueue(workUnit);
}
#endregion Public Methods
}
Work command
This class describes the work that needs to be done and any arguments that might be provided.
enum WorkCommand
{
Initialize
}
Work unit
This enumeration defines the various tasks that can be performed by the COM.
class WorkUnit
{
#region Public Properties
public WorkCommand Command { get; private set; }
public object[] Arguments { get; private set; }
#endregion Public Properties
#region Constructor
public WorkUnit(WorkCommand command, object[] arguments)
{
Command = command;
Arguments = arguments == null
? new object[0]
: arguments;
}
#endregion Constructor
}
Owner
This is a sample of the class that owns or spawns the Communication with the COM and is an abstraction over the Communication for use in the rest of the application.
class COMController
{
#region Public Events
/// This event is raised when the COM object has been initialized
public event EventHandler OnInitialize;
#endregion Public Events
#region Constructor
/// Creates a new COMController instance and starts the communication
public COMController()
{
var communicationThread = new Thread(() =>
{
Communication.StartCommunication();
});
communicationThread.SetApartmentState(ApartmentState.STA);
communicationThread.Start();
Communication.OnCOMInitialized += HandleCOMInitialized;
}
#endregion Constructor
#region Private Methods
/// Handles the initialized event raised from the Communication
private void HandleCOMInitialized()
{
OnInitialize?.Invoke(this, EventArgs.Emtpy);
}
#endregion Private Methods
#region Public Methods
/// Requests that the COM object be initialized
public void Initialize()
{
Communication.InitializeCOM();
}
#endregion Public Methods
}
The problem
Now, take a look at the Communication.StartCommunication() method, more specifically this part:
...
// [Place for a delaying logic]
...
If this line is substituted with the following:
await Task.Delay(TimeSpan.FromMilliseconds(100)).ConfigureAwait(false);
// OR
await Task.Delay(TimeSpan.FromMilliseconds(100)).ConfigureAwait(true);
during inspection the final stop - Communication.InternalInitializeCOM() the apartment of the thread seems to be MTA.
However, if the delaying logic is changed to
Thread.Sleep(100);
the CommunicationInternalInitializeCOM() method seems to be executed in a STA state.
The inspection was done by Thread.CurrentThread.GetApartmentState().
The Question
Can anyone explain to me why does Task.Delay break the STA state? Or am I doing something else that is wrong here?
Thank you!
Thank you for taking all this time to read the question! Have a great day!
Hans has nailed it. Technically, your code is breaking because there's no SynchronizationContext captured by the await. But even if you write one, it won't be enough.
The one big problem with this approach is that your STA thread isn't pumping. STA threads must pump a Win32 message queue, or else they're not STA threads. SetApartmentState(ApartmentState.STA) is just telling the runtime that this is an STA thread; it doesn't make it an STA thread. You have to pump messages for it to be an STA thread.
You can write that message pump yourself, though I don't know of anyone brave enough to have done this. Most people install a message pump from WinForms (a la Hans' answer) or WPF. It may also be possible to do this with a UWP message pump.
One nice side effect of using the provided message pumps is that they also provide a SynchronizationContext (e.g., WinFormsSynchronizationContext / DispatcherSynchronizationContext), so await works naturally. Also, since every .NET UI framework defines a "run this delegate" Win32 message, the underlying Win32 message queue can also contain all the work you want to queue to your thread, so the explicit queue and its "runner" code is no longer necessary.
Because after await Task.Delay() statement , your code runs inside one of the ThreadPool thread, and since the ThreadPool threads are MTA by design.
var th = new Thread(async () =>
{
var beforAwait = Thread.CurrentThread.GetApartmentState(); // ==> STA
await Task.Delay(1000);
var afterAwait = Thread.CurrentThread.GetApartmentState(); // ==> MTA
});
th.SetApartmentState(ApartmentState.STA);
th.Start();

is below class thread safe ? explain

Can someone explain whether or not I can call the below class "thread safe"?
As far as I know, we can call something thread safe if we are not breaking existing functionality
Example:
public class BackgroundWorker
{
private readonly IDictionary<string, RunningTask> _runningTasks = new ConcurrentDictionary<string, RunningTask>();
/// <summary>
/// Executes async job for the specified key, only one at a time.
/// </summary>
/// <param name="key"></param>
public void Enqueue(string key)
{
if (_runningTasks.ContainsKey(key))
{
_runningTasks[key].Repeat = true;
return;
}
_runningTasks[key] = new RunningTask();
ExecuteTask(key);
}
private void ExecuteTask(string key)
{
Task.Run(() =>
{
// Do something
if (_runningTasks[key].Repeat)
{
_runningTasks[key].Repeat = false;
ExecuteTask(key);
return;
}
_runningTasks.Remove(key);
});
}
private class RunningTask
{
/// <summary>
/// Flag to repeat a task after completion.
/// </summary>
public bool Repeat { get; set; }
}
}
I don't think so because _runningTasks is shared object and your method Enqueue is writing on this shared object. For example its possible when one thread already executed line number y, another thread will evaluate condition check in line number x as true - which might not be intention.
public void Enqueue(string key)
{
if (_runningTasks.ContainsKey(key)) /*say line no : x */
{
_runningTasks[key].Repeat = true;
return;
}
_runningTasks[key] = new RunningTask(); /*say line no:y*/
ExecuteTask(key);
}
Using ConcurrentDictionary will just ensure no two threads can read/write to/from the dictionary same time.
To your second point :
As far as I know, we can call something thread safe if we are not
breaking existing functionality
No this is not the definition of thread safe (might be ok to say one of desirable outcome in multi threaded environment) I would recommend to read this post for official meaning rather.

Cross thread UI component call

Is this an appropriate way of handling cross-thread operations?
Should I use a new property name, something like "EditValueThreadSafe" instead of overriding "EditValue"? I don't think there is an issue with the changes to the implementation of EditValue, as the base property is called regardless.
namespace MyApplication.Components
{
using System.Windows.Forms;
/// <summary>
/// Thread-safe implementation of the DevExpress.XtraEditors.ComboBoxEdit class.
/// </summary>
public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
{
/// <summary>
/// Gets or sets the edit value.
/// </summary>
/// <value>The edit value.</value>
public override object EditValue
{
get
{
return base.EditValue;
}
set
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(delegate
{
this.SetEditValue(value);
}));
}
else
{
this.SetEditValue(value);
}
}
}
/// <summary>
/// Sets the edit value.
/// </summary>
/// <param name="value">The value.</param>
private void SetEditValue(object value)
{
base.EditValue = value;
}
}
}
You can also delegate to another method that does the work, and in that method, if on the wrong thread, (BeginInvoke returns true), then call the same method back again. Doing that that eliminates the need to duplicate code.
public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
{
public override object EditValue
{
get
{
return base.EditValue;
}
set
{
SetValue(value);
}
}
private void delegate SetValueDlg(object valeu);
private void SetValue(object value)
{
if (this.InvokeRequired)
this.BeginInvoke(
(SetValueDlg)SetValue, // calls itself, but on correct thread
new object[] { value });
else
base.editValue = value;
}
}
You can also use the Action() generic class to eliminate need to create explicit delegate class...
public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
{
public override object EditValue
{
get { return base.EditValue; }
set { SetValue(value); }
}
private void SetValue(object value)
{
if (this.InvokeRequired)
this.BeginInvoke(
new Action<object>(SetValue), // calls itself, but on correct thread
new object[] { value });
else
base.editValue = value;
}
}
It's thread-safe, yes, though be wary of overriding a property and fundamentally changing the behaviour. Changing the implentation is fine, but this property now behaves very differently, removing the possibility of a specific exception but introducing a possible deadlock or blocking condition, which impacts on the calling code.
So yes, this is the correct use of InvokeRequired & Invoke, but I'd recommend creating a separate, purpose-specific and thread-safe property that is advertised as such.
My UI methods like yours end up looking like this:
public void setStatusLabelText(String s)
{
if (footerStatusLabel.InvokeRequired) {
StringUpdateInvokeDelegate callback = new StringUpdateInvokeDelegate(setStatusLabelText);
this.Invoke(callback, new object[] { s });
}
else {
this.footerStatusLabel.Text = s;
}
}
(this may be old for .net these days - but the point is that you can just do the operation inside this method if you are already on the right thread - makes it a little less irritating to read, but still annoying compared to Java, IMO).
I'll inject my 2 cents here. The actual calls to InvokeRequired/BeginInvoke/Invoke are not entirely thread safe. (see Avoiding the woes of Invoke/BeginInvoke in cross-thread WinForm event handling?) I would recommend finding some way of isolating the calls to these in a single place, utility api, extension method, or the like. In the article above there is complete code for a class that wraps a delegate to provide thread-safe behavior.

Raise Events in .NET on the main UI thread

I'm developing a class library in .NET that other developers will consume eventually. This library makes use of a few worker threads, and those threads fire status events that will cause some UI controls to be updated in the WinForms / WPF application.
Normally, for every update, you would need to check the .InvokeRequired property on WinForms or equivalent WPF property and invoke this on the main UI thread for updating. This can get old quickly, and something doesn't feel right about making the end developer do this, so...
Is there any way that my library can fire/invoke the events/delegates from the main UI thread?
In particular...
Should I automatically "detect" the "main" thread to use?
If not, should I require the end developer to call some (pseudo) UseThisThreadForEvents() method when the application starts so I can grab the target thread from that call?
Your library could check the Target of each delegate in the event's invocation list, and marshal the call to the target thread if that target is ISynchronizeInvoke:
private void RaiseEventOnUIThread(Delegate theEvent, object[] args)
{
foreach (Delegate d in theEvent.GetInvocationList())
{
ISynchronizeInvoke syncer = d.Target as ISynchronizeInvoke;
if (syncer == null)
{
d.DynamicInvoke(args);
}
else
{
syncer.BeginInvoke(d, args); // cleanup omitted
}
}
}
Another approach, which makes the threading contract more explicit, is to require clients of your library to pass in an ISynchronizeInvoke or SynchronizationContext for the thread on which they want you to raise events. This gives users of your library a bit more visibility and control than the "secretly check the delegate target" approach.
In regard to your second question, I would place the thread marshalling stuff within your OnXxx or whatever API the user code calls that could result in an event being raised.
Here's itwolson's idea expressed as an extension method which is working great for me:
/// <summary>Extension methods for EventHandler-type delegates.</summary>
public static class EventExtensions
{
/// <summary>Raises the event (on the UI thread if available).</summary>
/// <param name="multicastDelegate">The event to raise.</param>
/// <param name="sender">The source of the event.</param>
/// <param name="e">An EventArgs that contains the event data.</param>
/// <returns>The return value of the event invocation or null if none.</returns>
public static object Raise(this MulticastDelegate multicastDelegate, object sender, EventArgs e)
{
object retVal = null;
MulticastDelegate threadSafeMulticastDelegate = multicastDelegate;
if (threadSafeMulticastDelegate != null)
{
foreach (Delegate d in threadSafeMulticastDelegate.GetInvocationList())
{
var synchronizeInvoke = d.Target as ISynchronizeInvoke;
if ((synchronizeInvoke != null) && synchronizeInvoke.InvokeRequired)
{
retVal = synchronizeInvoke.EndInvoke(synchronizeInvoke.BeginInvoke(d, new[] { sender, e }));
}
else
{
retVal = d.DynamicInvoke(new[] { sender, e });
}
}
}
return retVal;
}
}
You then just raise your event like so:
MyEvent.Raise(this, EventArgs.Empty);
You can use the SynchronizationContext class to marshall calls to the UI thread in WinForms or WPF by using SynchronizationContext.Current.
I liked Mike Bouk's answer (+1) so much, I incorporated it into my codebase. I am concerned that his DynamicInvoke call will throw a runtime exception if the Delegate it invokes is not an EventHandler delegate, due to mismatched parameters. And since you're in a background thread, I assume you may want to call the UI method asynchronously and that you are not concerned with whether it ever finishes.
My version below can only be used with EventHandler delegates and will ignore other delegates in its invocation list. Since EventHandler delegates return nothing, we don't need the result. This allows me to call EndInvoke after the asynchronous process completes by passing the EventHandler in the BeginInvoke call. The call will return this EventHandler in IAsyncResult.AsyncState by way of the AsynchronousCallback, at which point EventHandler.EndInvoke is called.
/// <summary>
/// Safely raises any EventHandler event asynchronously.
/// </summary>
/// <param name="sender">The object raising the event (usually this).</param>
/// <param name="e">The EventArgs for this event.</param>
public static void Raise(this MulticastDelegate thisEvent, object sender,
EventArgs e)
{
EventHandler uiMethod;
ISynchronizeInvoke target;
AsyncCallback callback = new AsyncCallback(EndAsynchronousEvent);
foreach (Delegate d in thisEvent.GetInvocationList())
{
uiMethod = d as EventHandler;
if (uiMethod != null)
{
target = d.Target as ISynchronizeInvoke;
if (target != null) target.BeginInvoke(uiMethod, new[] { sender, e });
else uiMethod.BeginInvoke(sender, e, callback, uiMethod);
}
}
}
private static void EndAsynchronousEvent(IAsyncResult result)
{
((EventHandler)result.AsyncState).EndInvoke(result);
}
And the usage:
MyEventHandlerEvent.Raise(this, MyEventArgs);
I found relying on the method being an EventHandler doesn't always work and ISynchronizeInvoke doesn't work for WPF. My attempt therefore looks like this, it may help someone:
public static class Extensions
{
// Extension method which marshals events back onto the main thread
public static void Raise(this MulticastDelegate multicast, object sender, EventArgs args)
{
foreach (Delegate del in multicast.GetInvocationList())
{
// Try for WPF first
DispatcherObject dispatcherTarget = del.Target as DispatcherObject;
if (dispatcherTarget != null && !dispatcherTarget.Dispatcher.CheckAccess())
{
// WPF target which requires marshaling
dispatcherTarget.Dispatcher.BeginInvoke(del, sender, args);
}
else
{
// Maybe its WinForms?
ISynchronizeInvoke syncTarget = del.Target as ISynchronizeInvoke;
if (syncTarget != null && syncTarget.InvokeRequired)
{
// WinForms target which requires marshaling
syncTarget.BeginInvoke(del, new object[] { sender, args });
}
else
{
// Just do it.
del.DynamicInvoke(sender, args);
}
}
}
}
// Extension method which marshals actions back onto the main thread
public static void Raise<T>(this Action<T> action, T args)
{
// Try for WPF first
DispatcherObject dispatcherTarget = action.Target as DispatcherObject;
if (dispatcherTarget != null && !dispatcherTarget.Dispatcher.CheckAccess())
{
// WPF target which requires marshaling
dispatcherTarget.Dispatcher.BeginInvoke(action, args);
}
else
{
// Maybe its WinForms?
ISynchronizeInvoke syncTarget = action.Target as ISynchronizeInvoke;
if (syncTarget != null && syncTarget.InvokeRequired)
{
// WinForms target which requires marshaling
syncTarget.BeginInvoke(action, new object[] { args });
}
else
{
// Just do it.
action.DynamicInvoke(args);
}
}
}
}
You can store the dispatcher for the main thread in your library, use it to check if you are running on the UI thread, and execute on the UI thread through it if necessary.
The WPF threading documentation provides a good introduction and samples on how to do this.
Here is the gist of it:
private Dispatcher _uiDispatcher;
// Call from the main thread
public void UseThisThreadForEvents()
{
_uiDispatcher = Dispatcher.CurrentDispatcher;
}
// Some method of library that may be called on worker thread
public void MyMethod()
{
if (Dispatcher.CurrentDispatcher != _uiDispatcher)
{
_uiDispatcher.Invoke(delegate()
{
// UI thread code
});
}
else
{
// UI thread code
}
}
I know this is an old thread, but seeing as it really helped me get started on building something similar, so I want to share my code. Using the new C#7 features, I was able to create a thread aware Raise function. It uses the EventHandler delegate template, and the C#7 pattern matching, and LINQ to filter and set type.
public static void ThreadAwareRaise<TEventArgs>(this EventHandler<TEventArgs> customEvent,
object sender, TEventArgs e) where TEventArgs : EventArgs
{
foreach (var d in customEvent.GetInvocationList().OfType<EventHandler<TEventArgs>>())
switch (d.Target)
{
case DispatcherObject dispatchTartget:
dispatchTartget.Dispatcher.BeginInvoke(d, sender, e);
break;
case ISynchronizeInvoke syncTarget when syncTarget.InvokeRequired:
syncTarget.BeginInvoke(d, new[] {sender, e});
break;
default:
d.Invoke(sender, e);
break;
}
}
I like these answers and examples but inherently by standard you are writing the library all wrong. It's important not to marshal your events to other threads for the sake of others. Keep your events fired where they are and handled where they belong. When the time comes for that event to change threads it's important to let the end developer do that at that point in time.

Categories

Resources