I'm having trouble invoking an event from a secondary thread in the main thread. The event handler is not executed on main thread. Can anyone give me some pointers on what I'm doing wrong.
Thanks
namespace ThreadSyncExample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("MainThread: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
Execute execThe = new Execute();
execThe.FinishedThread += (src, arg) =>
{
//This shoould be executed on MainThread right?
Console.WriteLine("Thread Id: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
};
execThe.Run();
Console.ReadKey();
}
}
class Execute
{
public void Run()
{
Thread exec = new Thread(() =>
{
Console.WriteLine("Worker Thread : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
OnFinishedThread();
});
exec.Start();
}
public event EventHandler FinishedThread;
protected virtual void OnFinishedThread()
{
if (null != FinishedThread)
{
EventArgs args = new EventArgs();
FinishedThread(this, EventArgs.Empty);
}
}
}
}
C# events are basically just an easy-to-use collection of delegates and "firing" an event just causes the runtime to loop through all of the delegates and fire them one at a time.
So your OnFinishedThread event handler is getting called on the Worker thread.
If you want your event on the main thread, you have to Invoke() it.
EDIT :
It appears that you don't have access to forms, or WPF (so you don't have access to Invoke() either)
So you have to manually marshall the call to the main thread by thread synchronization process. It's generally a pain.
Probably the easiest solution would be to simply use a BackgroundWorker because this way you no longer need to manualy marshal the calls to the main thread.
var worker = new BackgroundWorker();
worker.DoWork += (sender, e) =>
{
// call the XYZ function
e.Result = XYZ();
};
worker.RunWorkerCompleted += (sender, e) =>
{
// use the result of the XYZ function:
var result = e.Result;
// Here you can safely manipulate the GUI controls
};
worker.RunWorkerAsync();
the FinishedThread() event handler will be executed on the same thread as Execute.Run() is executed on. Just because you defined the body of the FinishedThread event handler in main() doesn't mean that main() somehow defines it's execution context.
Some mechanisms you can use to perform thread marshalling:
Use a system.windows.forms.control and use the Invoke method to marshal a function call back to the thread the control was created on. Under the hood, this will use features of the Windows Message Loop to handle the actual marshal
Use synchronization primitives to handle the marshalling manually.
Rather than re-iterate what has already been stated, check this answer for more information on marshalling:
Marshall to a thread manually
Related
I want to write a synchronous test that calls into some asynchronous product tasks.
In the example below, DoSomething() is called by a separate thread, and then it sets the SomethingCompleted event.
In my test code, how do I wait for SomethingCompleted to be set?
public event Action<Result> SomethingCompleted;
public void DoSomething()
{
Something();
this.SomethingCompleted(new Result("Success"));
}
using (var evt = new ManualResetEvent()) {
Action<Result> handler = _ => evt.Set();
SomethingCompleted += handler;
evt.WaitOne();
SomethingCompleted -= handler; //cut object reference to help GC
}
If required you can unsubscribe from the event after the wait has completed. That way the event will not keep the delegate and closure instance alive.
You can extract this into a reusable helper method/extension.
// test case
public void Test()
{
var yourObj = new YourObj();
var done = false;
Result result;
yourObj.SomethingCompleted += (finalResult) => {
result=finalResult;
done=true;
};
yourObj.DoSomething();
while(!done) Thread.Sleep(200);
if(result != theExpectedResult) kaboom();
}
What about subscribing to an event and "polling" the lambda until result comes available? This should work.
You're using the wrong type of event. The event you're using is a callback. In the code you supplied, the delegates attached to the SomethingCompleted event are going to be called on the same thread as DoSomething.
What you want is thread synchronization, using an event like AutoResetEvent or ManualResetEvent, which have nothing to do with the framework/language-level event that you're using. You could do something like this:
void MainThreadProc()
{
// create thread synchronization event
using (var evt = new ManualResetEvent(false))
{
// start background operation
ThreadPool.QueueUserWorkItem(BackgroundThreadProc, evt);
// this line will block until BackgroundThreadProc sets the event
evt.WaitOne();
}
// resume main thread operations here
...
}
void BackgroundThreadProc(object o)
{
// get event from argument
var evt = (ManualResetEvent) o;
// do the deed
...
// set event to signal completion
evt.Set();
}
This is just one of a number of different ways to do this. Alternatives include Parallel LINQ or the Task Parallel Library (both of which are best used with parallel operations, not just a single background operation). If you don't want to block the main thread, look at BackgroundWorker.
I have a c# .NET winforms app making this async call:
simpleDelegate.BeginInvoke(null, null);
My function is being called by the delegate and that all works great. The problem is, after the function finishes on the worker thread, I need the main thread to update some controls on my winform. If the worker thread tries to update these controls, .NET freaks out. But I need the main thread to remain responsive to user actions, and then call my function UpdateFormAfterServerCall() ONLY AFTER the worker thread finishes calling the async function.
I would greatly appreciate if you can give me a concise code sample, rather than abstractly explain how to do this. I've read a hundred explanations already, and am just having trouble wiring it together correctly.
Note: Before the BeginInvoke I have:
simpleDelegate = new MethodInvoker(CallServer);
From different thread if you want to update GUI which is owned by another thread use MethodInvoker
if(control.InvokeRequired)
control.Invoke( (MethodInvoker) ( ()=> updating_function() ) );
else
updating_function();
You could use a BackgroundWorker:
BackgroundWorker bw = new BackgroundWorker();
string result = null;
bw.DoWork += (s, e) =>
{
// Executes on background thread.
// UI remains responsive to user activity during this time.
result = CallServer();
};
bw.RunWorkerCompleted += (s, e) =>
{
// Executes on UI thread upon completion.
resultTextBox.Text = result;
};
bw.RunWorkerAsync();
The Control class (Form is a Control as well) has an Invoke method, you can call this from any thread to execute code on the GUI thread.
In addition, Control has a convenient InvokeRequired property that informs you whether you are on the GUI thread already. You could for instance create the following method in your form:
public class MyForm
{
// ...
public void UpdateMe()
{
if (InvokeRequired)
{
Invoke(new Action(UpdateMe));
return;
}
// Code to update the control, guaranteed to be on the GUI thread
}
}
Here is the code sample [what you want exactly] -
http://www.yoda.arachsys.com/csharp/threads/winforms.shtml
& you can read about all flavours of async here -
http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.100).aspx
I'm running some scripts in runtime, but it's freezing my UI, I'm calling the CodeProvider inside a Thread, but it still freezing.
In my form I call:
var mre = new ManualResetEvent(false);
Thread tr = new Thread(() =>
{
Script sp = new Script();
code = textBox.Text;
sp.Comp(code);
mre.Set();
});
tr.Start();
mre.WaitOne();
I'm using the mre.WaitOne() because I want to wait the thread finish to keep running my code.
Tried to use the same way inside the Compile method too:
public bool Comps(string code)
{
var mre = new ManualResetEvent(false);
Thread tr = new Thread(() =>
{
//Code to generate a CompilerResult and generate the assembly
Run();
mre.Set();
});
tr.Start();
mre.WaitOne();
return true;
}
But while it's waiting it still freezing the UI.
Any ideas?
Thanks
I'm using the mre.WaitOne() because I want to wait the thread finish
to keep running my code.
What did you expect to happen if you force the calling thread to freeze until your processing thread has completed processing? Doing it this way, there is no point in having that extra thread and if the calling thread is the UI thread, of course it will freeze.
If you do background processing you cannot wait for the result synchronously, instead you have to notify the UI in some sort of fashion that the processing is done, i.e. using a callback or dispatching the result back to the UI in some other form.
The entire point of multi-threading is to allow the Thread to execute on it's own, independent of any other threads. What you want to do is use a callback to signal the completion of your thread and then have your UI respond to the completion.
The BackgroundWorker class has an event already built in for this purpose.
There are three events you want to subscribe to:
bw.DoWork +=
new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged +=
new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
DoWork is where your work will happen. ProgressChanged allows you to update the UI of progress. RunWorkerCompleted will pop the event with your DoWork function has completed.
This object handles the threading and can be set to run asynchronously by running the bw.RunWorkerAsync() call.
See the following page for detail for this:
http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx
As an example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(String.Format("UI thread: {0}", Thread.CurrentThread.ManagedThreadId));
this.Invoke(new MethodInvoker(delegate() { MessageBox.Show(String.Format("Invoke thread: {0}", Thread.CurrentThread.ManagedThreadId)); }));
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
MessageBox.Show(String.Format("Worker thread: {0}", Thread.CurrentThread.ManagedThreadId));
}
}
This example can be built by adding one button and one background worker to a form. Wire up the events through the events designer for the button1_Click and the backgroundWorker1_DoWork function. You should have three MessagesBoxes that pop up after clicking button1. You'll notice the Id for the UI thread and the Invoke thread are the same, which means that any processing you do from the invoke will cause your UI thread to wait. The third popup is from the worker thread, which has a different ID.
Use BeginInvoke when done. For example:
delegate void MyAction();
void Form1_Load( object sender, EventArgs e )
{
Thread tr = new Thread( () =>
{
Script sp = new Script();
code = textBox.Text;
sp.Comp(code);
BeginInvoke( new MyAction( ThreadOperationEnded ) );
} );
tr.Start();
}
void ThreadOperationEnded()
{
MessageBox.Show( "Finished!" );
}
I'm working on asynchronous operation which needs to invoke further asynchronous tasks. I'm trying to keep it simple by using BackgroundWorkers, with the result being that one BackgroundWorker's DoWork() callback calls a method which creates a second BackgroundWorker, like so (minus error checking and all that jazz for brevity):
class Class1
{
private BackgroundWorker _worker = null;
public void DoSomethingAsync()
{
_worker = new BackgroundWorker();
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
_worker.RunWorkerAsync();
}
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
Class2 foo = new Class2();
foo.DoSomethingElseAsync();
while(foo.IsBusy) Thread.Sleep(0); // try to wait for foo to finish.
}
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// do stuff
}
}
class Class2
{
private BackgroundWorker _worker = null;
Thread _originalThread = null;
public AsyncCompletedEventHandler DoSomethingCompleted;
public bool IsBusy { get { return _worker != null && _worker.IsBusy; } }
public void DoSomethingElseAsync()
{
_originalThread = Thread.CurrentThread;
_worker = new BackgroundWorker();
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
_worker.RunWorkerAsync();
}
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
// do stuff
}
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.Assert(Thread.CurrentThread == _originalThread); // fails
// Assuming the above Assert() were excluded, the following event would be raised on the wrong thread.
if (DoSomethingCompleted != null) DoSomethingCompleted(this, new AsyncCompletedEventArgs(e.Error, e.Cancelled, null));
}
}
So the problem is, I'm expecting Class2._Worker_RunWorkerCompleted() to execute on the same thread on which Class2.DoSomethingElseAsync() was called. This never happens - instead, the callback runs on a completely new thread.
Here's my suspicion: Class1's _worker_DoWork() never returns, which means that thread would never get back to an event listener, even if one existed (I suspect one doesn't). On the other hand, if _worker_DoWork() did return, Class1's BackgroundWorker would automatically finish prematurely - it needs to wait for Class2 to finish working before it can finish its work.
That leads to two questions:
Is my suspicion correct?
What's the best way to nest asynchronous operations like this? Can I salvage the BackgroundWorker approach, or is there some other, more suitable technique?
If a BackgroundWorker is created on the UI thread, DoWork will run on a thread pool thread and RunWorkerCompleted will run on the UI thread.
If a BackgroundWorker is created on a background thread (ie not the UI thread) DoWork will still run on a thread pool thread and RunWorkerCompleted will also run on a thread pool thread.
In your case, since you can't marshal a call to an arbitrary (thread pool) thread, you won't be able to guarantee the behaviour you want, although you might want to take a look at System.Threading.SynchronizationContext.
You should use ManualResetEvent to communicate between threads:
http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent%28VS.71%29.aspx
Firstly, I can't see anywhere that actually starts running the worker. You could change the DoSomethingAsync method (also add the call to the DoSomethingElseAsync method in Class2)
public void DoSomethingAsync()
{
_worker = new BackgroundWorker();
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
_worker.RunWorkerAsync(); // add this line to start it
}
Secondly, the work handler (the _worker_DoWork method) is not guaranteed to be on the same thread as the call to DoSomethingAsync - this is the whole point of the Background Worker. ie/ to do work on another thread. The same applies for worker complete handler (the _worker_RunWorkerCompleted method).
Finally, It doesn't seem to make sense to attach the two different background workers unless the top level one (Class1) always requires Class2 work to happen too. You would be better of having a single manager to handle each background worker.
I use BackgroundWorker most of the time in the win form apps to show progress as I'm getting data. I was under impression that Work_completed is guaranteed to be executed on Main UI thread but it's not. If we create a thread and call the worker.RunWorkerAsync within it, it breaks if we try to update any gui control. Here is an example
private void StartButton_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(new ThreadStart(PerformWorkerTask));
_worker = new BackgroundWorker();
thread1.Start();
}
public void PerformWorkerTask()
{
_worker.DoWork += delegate
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(100);
}
};
_worker.RunWorkerCompleted += delegate
{
// this throws exception
MessageLabel.Text = "Completed";
};
_worker.RunWorkerAsync();
}
How can we make backgroundworker work in this case?
RunWorkerAsync does its thread-synchronization magic by getting the SynchronizationContext from the thread that it is called on. It then guarantees that the events will be executed on the correct thread according to the semantics of the SynchronizationContext it got. In the case of the WindowsFormsSynchronizationContext, which is what is automatically used if you're using WinForms, the events are synchronized by posting to the message queue of the thread that started the operation. Of course, this is all transparent to you until it breaks.
EDIT: You MUST call RunWorkerAsync from the UI thread for this to work. If you can't do it any other way, your best bet is to invoke the beginning of the operation on a control so that the worker is started on the UI thread:
private void RunWorker()
{
_worker = new BackgroundWorker();
_worker.DoWork += delegate
{
// do work
};
_worker.RunWorkerCompleted += delegate
{
MessageLabel.Text = "Completed";
};
_worker.RunWorkerAsync();
}
// ... some code that's executing on a non-UI thread ...
{
MessageLabel.Invoke(new Action(RunWorker));
}
From your example it's hard to see what good the Thread (thread1) is, but if you really do need this thread1 then I think your only option is to use MainForm.Invoke() to execute RunWorkerAsync() (or a small method around it) on the main thread.
Added: You can use something like this:
Action a = new Action(_worker.RunWorkerAsync);
this.Invoke(a);
It sounds like the issue is just that you want to make a change to a GUI component and you aren't actually sure if you're on the GUI thread. Dan posted a valid method of setting a GUI component property safely, but I find the following shortcut method the simplest:
MessageLabel.Invoke(
(MethodInvoker)delegate
{
MessageLabel.Text = "Hello World";
});
If there are any issues with this approach, I'd like to know about them!
In the code you have presented here, you're adding the delegates for the BackgroundWorker events in a separate thread from the UI thread.
Try adding the event handlers in the main UI thread, and you should be okay.
You could probably make your existing code work by doing:
this.Dispatcher.BeginInvoke(() => MessageLabel.Text = "Completed")
instead of
MessageLabel.Text = "Completed"
You're probably having cross-thread data access issues, so you have to ensure that you access properties of MessageLabel on your UI thread. This is one way to do that. Some of the other suggestions are valid too. The question to ask yourself is: why are you creating a thread that does nothing other than create a BackgroundWorker thread? If there's a reason, then fine, but from what you've shown here there's no reason you couldn't create and start the BackgroundWorker thread from your event handler, in which case there would be no cross-thread access issue because the RunWorkerCompleted event handler will call its delegates on the UI thread.
I believe BackgroundWorker is designed to automatically utilize a new thread. Therefore creating a new thread just to call RunWorkerAsync is redundant. You are creating a thread just to create yet another thread. What's probably happening is this:
You create a new thread from thread 1 (the GUI thread); call this thread 2.
From thread 2, you launch RunWorkerAsync which itself creates yet another thread; call this thread 3.
The code for RunWorkerCompleted runs on thread 2, which is the thread that called RunWorkerAsync.
Since thread 2 is not the same as the GUI thread (thread 1), you get an illegal cross-thread call exception.
(The below suggestion uses VB instead of C# since that's what I'm more familiar with; I'm guessing you can figure out how to write the appropriate C# code to do the same thing.)
Get rid of the extraneous new thread; just declare _worker WithEvents, add handlers to _worker.DoWork and _worker.RunWorkerCompleted, and then call _worker.RunWorkerAsync instead of defining a custom PerformWorkerTask function.
EDIT: To update GUI controls in a thread-safe manner, use code like the following (more or less copied from this article from MSDN):
delegate void SetTextCallback(System.Windows.Forms.Control c, string t);
private void SafeSetText(System.Windows.Forms.Control c, string t)
{
if (c.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SafeSetText);
d.Invoke(d, new object[] { c, t });
}
else
{
c.Text = t;
}
}
The best way to deal with these generic problems is to deal it once. Here I'm posting a small class that wraps the backgroupdworker thread and makes sure that the workcompleted always gets executed on the UI thread.
using System.Windows.Forms;
namespace UI.Windows.Forms.Utilities.DataManagment
{
public class DataLoader
{
private BackgroundWorker _worker;
private DoWorkEventHandler _workDelegate;
private RunWorkerCompletedEventHandler _workCompleted;
private ExceptionHandlerDelegate _exceptionHandler;
public static readonly Control ControlInvoker = new Control();
public DoWorkEventHandler WorkDelegate
{
get { return _workDelegate; }
set { _workDelegate = value; }
}
public RunWorkerCompletedEventHandler WorkCompleted
{
get { return _workCompleted; }
set { _workCompleted = value; }
}
public ExceptionHandlerDelegate ExceptionHandler
{
get { return _exceptionHandler; }
set { _exceptionHandler = value; }
}
public void Execute()
{
if (WorkDelegate == null)
{
throw new Exception(
"WorkDelegage is not assinged any method to execute. Use WorkDelegate Property to assing the method to execute");
}
if (WorkCompleted == null)
{
throw new Exception(
"WorkCompleted is not assinged any method to execute. Use WorkCompleted Property to assing the method to execute");
}
SetupWorkerThread();
_worker.RunWorkerAsync();
}
private void SetupWorkerThread()
{
_worker = new BackgroundWorker();
_worker.WorkerSupportsCancellation = true;
_worker.DoWork += WorkDelegate;
_worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Error !=null && ExceptionHandler != null)
{
ExceptionHandler(e.Error);
return;
}
ControlInvoker.Invoke(WorkCompleted, this, e);
}
}
}
And here is the usage. One thing to note is that it exposes a static property ControlInvoker that needs to be set only once (you should do it at the beginning of the app load)
Let's take the same example that I posted in question and re write it
DataLoader loader = new DataLoader();
loader.ControlInvoker.Parent = this; // needed to be set only once
private void StartButton_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(new ThreadStart(PerformWorkerTask));
_worker = new BackgroundWorker();
thread1.Start();
}
public void PerformWorkerTask()
{
loader.WorkDelegate = delegate {
// get any data you want
for (int i = 0; i < 10; i++)
{
Thread.Sleep(100);
}
};
loader.WorkCompleted = delegate
{
// access any control you want
MessageLabel.Text = "Completed";
};
loader.Execute();
}
Cheers