I have some code as follows. This is running on "Thread 2"
WebBrowser browser = this.webBrowser
browser.Invoke(new MethodInvoker(delegate { browser.Document.GetElementById("somebutton").InvokeMember("click"); }));
Thread.Sleep(500);
browser.Invoke(new MethodInvoker(delegate { browser.Document.GetElementById("username").SetAttribute("value", username); }));
//folowed by several more similar statments
Essentially I am Invoking some methods on a WebBrowser control created on a different thread, "Thread 1".
If the element on the current page loaded in browser does not contain an element "somebtn" or "username", an exception is thrown from "Thread 1".
Is there any way to catch that exception on "Thread 2"? I know I could use try catches within the delegates and have a special delegate that returns some value(like an exception), but is there any way around that options?
Note*: I require the Thread.Sleep as the particular page requires some delay between certain events. If there was some way to combine these events into a single delegate(while retaining some form of non-blocking delay), I think that could work and I would just wrap all of them in single try catch and create a delegate that returns an exception.
Although Control.Invoke() executes delegate over UI thread - it is still a synchronous call. Synchronous meaning Invoke will not return until the delegate has completed execution (or exception thrown). You can simply catch the exceptions thrown there.
WebBrowser browser = this.webBrowser;
try {
browser.Invoke(new MethodInvoker(delegate { browser.Document.GetElementById("somebutton").InvokeMember("click"); }));
Thread.Sleep(500);
browser.Invoke(new MethodInvoker(delegate { browser.Document.GetElementById("username").SetAttribute("value", username); }));
} catch(Exception e)
{
//catch in Thread 2
}
If you use WebBrowser.Invoke, all delegates are executes on the thread of the User Interface. So everything will be executed on one single thread. So in your question you want the UI thread to wait for itself? Assuming this is not what you want, I took some "freedom" in my answer:
There are multiple options, but I will show the most simple one:
Start both delegates with BeginInvoke.
Store the IAsyncResult of thread1 in a local variable.
Thread2 will do its work.
Thread2 will do the EndInvoke of thread1.
Code:
WebBrowser browser = this.webBrowser;
MethodInvoker thread1 = delegate
{
browser.Document.GetElementById("somebutton").InvokeMember("click");
};
IAsyncResult result1 = thread1.BeginInvoke(null, null);
Thread.Sleep(500);
MethodInvoker thread2 = delegate
{
browser.Document.GetElementById("username").SetAttribute("value", username);
try
{
thread1.EndInvoke(result1);
}
catch (Exception ex)
{
// Exception of thread1.
}
};
thread2.BeginInvoke(null, null);
Related
I need to control a camera from within an ASP.NET core api and all communication is via a pInvoke dll.
In the docs it explicitly states
To create a user thread and access the camera from that thread, be sure to execute CoInitializeEx( NULL,
COINIT_APARTMENTTHREADED ) at the start of the thread and CoUnInitialize() at the end.
e.g
CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0);
CoUninitialize()
My camera service works from a winforms application (STA) however when I move it over to my API, the callback does not fire when events happen.
I've tried wrapping the component in an STA thread and setting up an execution loop but callbacks still do not fire.
I think I might need a message pump but am unsure exactly how this should work.
Non working code:
Thread handlerThread;
handlerThread = new Thread(STAThreadLoop);
handlerThread.SetApartmentState(ApartmentState.STA);
handlerThread.Start();
and in the thread loop
void STAThreadLoop()
{
logger.LogInformation("Starting STAThreadLoop...");
lock (handlerThreadLock)
{
handlerSignal.Set();
while (!exitHandlerThreadLoop)
{
Thread.Yield();
Monitor.Wait(handlerThreadLock);
if (handlerThreadAction != null)
{
try
{
handlerThreadAction();
}
catch (Exception ex)
{
logger.LogError(ex, "Error executing action on STA thread: {ThreadName}", Thread.CurrentThread.Name);
}
}
Monitor.Pulse(handlerThreadLock);
}
}
}
and then to create the component
RunSTAAction(() =>
{
handler = new SDKHandler(loggerFactory.CreateLogger<SDKHandler>());
});
and the method to transition to the STA thread
void RunSTAAction(Action action)
{
if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
{
lock (handlerThreadLock)
{
handlerThreadAction = action;
Monitor.Pulse(handlerThreadLock);
Monitor.Wait(handlerThreadLock);
}
}
else
{
action();
}
}
Update: This is actually fixed, see answer below
I found a way to do this using the excellent answer by Noseratio in this question: StaTaskScheduler and STA thread message pumping
Effectively, we create an instance of the ThreadAffinityTaskScheduler and pass the WaitHelpers.WaitWithMessageLoop as a wait function.
ThreadAffinityTaskScheduler messageScheduler;
messageScheduler = new ThreadAffinityTaskScheduler(3, staThreads: true, waitHelper: WaitHelpers.WaitWithMessageLoop);
messageScheduler.Run(new Action(STAThreadLoop), CancellationToken.None);
Thread version results in unhandled exception, which crashes the app but the task version doesn't. Both are running exactly the same method Can someone explain the reason for this difference in exception behavior ?
Thread version:
try
{
new Thread(new ThreadStart(DoWork)).Start(); // do work throws exception
}
catch (Exception e)
{
Console.WriteLine(e);
}
static void DoWork()
{
Console.WriteLine("in thread");
throw new Exception();
}
Task version:
var errorTask = Task.Factory.StartNew<Func<string>>(() =>
{
Console.WriteLine("in task");
throw new Exception();
});
try
{
string result = errorTask.Result();
}
catch (Exception e)
{
Console.WriteLine(e);
}
Thread.Start starts new thread, but you're handling exception in another thread:
try
{
// DoWork throws exception in new thread;
// threads don't catch exceptions out-of-the-box
new Thread(new ThreadStart(DoWork)).Start();
}
catch (Exception e)
{
// you're handling exception in "old" thread
Console.WriteLine(e);
}
Task.Factory.StartNew starts new task. Task catches exception inside it to set its Status property:
var errorTask = Task.Factory.StartNew<Func<string>>(() =>
{
Console.WriteLine("in task");
// this exception will be caught in Task's base code,
// since tasks catch exceptions thrown by task methods;
// note, that this will be wrapped into AggregateException
throw new Exception();
});
when you're trying to get Task.Result, and task is in faulted state, it just re-throws exception:
// this will re-throw exception in calling thread
string result = errorTask.Result;
That's why your second catch catches it.
To shed some light on the topic one could consult the documentation for Task.Result<TResult>() (or the one for Task.Wait() for what it's worth).
Under thrown exceptions (particularly AggregateException) is says
An exception was thrown during the execution of the task. The AggregateException.InnerExceptions collection contains information about the exception or exceptions.
A Task is kind of a managed thread (in very simple terms) which gives us some merits, e.g. this exception handling when accessing Result or Wait (or using await). On the other hand a Thread will execute separately from the method you are calling it from. You start the thread an (virtually) immediately leave the try / catch block. There is no way to know for the thread that there is an associated try / catch. Basically the thread does not know anything about the calling function. The other way round, if the calling function blocked its own thread to wait for the thread it created, just to make use of the try / catch this would basically render creating new threads useless.
I've a main thread called t1:
Thread t1 => new Thread(UpdateResults);
that execute a method called UpdateResult this method require internet connection. Now sometimes the connection could be broken.
When the connection is down, the method UpdateResult return an exception and the thread t1 terminate the execution.
I need to execute again the thread t1 so I though to create another thread t2 that check recursively if the thread t1 is running or no.
Both thread are started automatically. This is the code of thread t2 method:
while (true)
{
if (!t1.IsAlive)
{
t1.Start();
}
}
this code unfortuntely slow down the app UI, 'cause is an infinite loop.
What I can do instead for fix this?
Instead of wasting another thread t2 just to watch t1, you may consider to change the method of thread t1:
Thread t1 = new Thread(o =>
{
while (true)
{
try
{
UpdateResult();
}
catch (Exception)
{
// do some error handling
}
Thread.Sleep(100);
}
});
So you catch the exception (without rethrowing it!) and prevent the crash of the whole thread.
This is of course only a simple example. You should try to catch only the specific exception for a broken connection and add proper error handling (e.g. logging etc.).
And adjust the time the thread should sleep according to your needs.
One approach to avoid an infinite polling is to Join the thread, and re-spawn it when it stops:
while (true) {
t1.Join();
t1 = ... // Make a replacement thread
t1.Start();
}
It goes without saying that this should not be done from UI thread, because Join() blocks indefinitely.
If you want to stick with your architecture, something as simple as waiting a second in each loop of Thread t2 would massively improve performance.
while (true)
{
if(!t1.isAlive)
{
t1.Start();
}
Thread.Sleep(1000);
}
(You can adjust the time to anything that makes sense in your context.)
Though instead of this multi-thread solution, i would ask: why does thread t1 terminate because of an Exception? You can catch it with a try-catch block.
Instead of UpdateResults call SafeUpdateResults which just says:
void SafeUpdateResults()
{
while (true)
{
try { UpdateResults(); }
catch (Exception e)
{
//track the Error if you want
Console.WriteLine("t1-Error: " + e.Message);
}
}
}
I would even recommend, going into the function UpdateResults() and catching the Exception right where it happens, and then reacting accordingly (though this here is arguably easier).
If I have the following situation:
Execute() creates a new thread and executes function GetSession() in it.
Execute() executes GetSession() again in it's own thread.
Execute() joins the thread from (1).
My question is:
What happens if GetSession() throws an exception from the thread spawned in (1) while the thread Execute() is running in is currently running GetSession() itself?
Does the exception re-thrown from the extra thread propagate up to Execute() and cause it to go to its handler even though it's from a different thread?
Here's some sample code to demonstrate the issue:
I just made this up in the window here (it's a mock-up), so appologies for syntax errors.
public void Execute()
{
//Some logon data for two servers.
string server1 = "x", server2 = "y", logon = "logon", password = "password";
//Varialbes to store sessions in.
MySession session1, session2;
try
{
//Start first session request in new thread.
Thread thread = new Thread(() =>
session1 = GetSession(server1, logon, password));
thread.Start();
//Start second request in current thread, wait for first to complete.
session2 = GetSession(server2, logon, password));
thread.Join();
}
catch(Exception ex)
{
//Will this get hit if thread1 throws an exception?
MessageBox.Show(ex.ToString());
return;
}
}
private MySession GetSession(string server, string logon, string password)
{
try
{
return new MySession(server, logon, password);
}
catch(Exception Ex)
{
throw(Ex);
}
}
What happens if GetSession() throws an exception from the thread spawned in (1) while the thread Execute() is running in is currently running GetSession() itself?
The threaded version will raise an unhandled exception, which will trigger AppDomain.UnhandledException. Unless this is explicitly handled there, it will tear down the application.
Does the exception re-thrown from the extra thread propagate up to Execute() and cause it to go to its handler even though it's from a different thread?
No. It will be unhandled.
Note that this is one of the advantages of the TPL. If you use Task instead of a Thread, you can make this propogate the exception back to the main thread:
try
{
//Start first session request in new thread.
Task<Session> task = Task.Factory.StartNew(() => GetSession(server1, logon, password));
//Start second request in current thread, wait for first to complete.
session2 = GetSession(server2, logon, password));
session1 = task.Result; // This blocks, and will raise an exception here, on this thread
}
catch(Exception ex)
{
// Now this will get hit
MessageBox.Show(ex.ToString());
return;
}
Note, however, that this will be an AggregateException, and requires special handling.
How could you find out that an Exception occurred in a Thread in a MultiThreaded Application ? and consecutively clean the resources ?
Because otherwise the Thread can be still remaining in memory and running.
As Sean has said, you have to do all exception handling and cleanup inside the thread method, you can't do it in the Thread initialization. For example:
public void Run()
{
try
{
Thread thread1 = new Thread(ThreadEntry1);
thread1.Start();
Thread thread2 = new Thread(ThreadEntry2);
thread2.Start();
}
catch (NotImplementedException)
{
// Neither are caught here
Console.WriteLine("Caught you");
}
}
private void ThreadEntry1()
{
throw new NotImplementedException("Oops");
}
private void ThreadEntry2()
{
throw new NotImplementedException("Oops2");
}
Instead, this approach is more self-contained and obviously also works:
public void Run()
{
Thread thread1 = new Thread(ThreadEntry1);
thread1.Start();
}
private void ThreadEntry1()
{
try
{
throw new NotImplementedException("Oops");
}
catch (NotImplementedException)
{
Console.WriteLine("Ha! Caught you");
}
}
If you want to know if the Thread has failed, then you should consider an array of WaitHandles, and signal back to your calling method. An alternative and simpler approach is to simply increment a counter each time a thread's operation finishes:
Interlocked.Increment(ref _mycounter);
If you're worried about this sort of thing then you should wrap your threads entry point in a try/catch block and do the cleanup explicitly. Any exception passing out of the thread entry point will cause your app to shut down.
A. You have a call stack, and you can catch it inside the thread and add the thread id to the log I guess...
If you wrap your thread in a good manner, you can add cleaing code to the catch section, terminating the thread if needed.
You can catch exceptions within threads like you would any normal function.
If your "work" function for a thread is called DoWork then do something like this:
private void DoWork(...args...)
{
try
{
// Do my thread work here
}
catch (Exception ex)
{
}
}
Eric Lippert has a recent post on the badness of exceptions occurring in worker threads. It's worth reading and understanding that an exception is "exceptional" and the only thing that you can be sure of after an exception in a worker thread is that you can no longer be sure of the state of your application.