Remove need for Invoke() by handling within threaded library - c#

Within a class library I'm writing I have a method allowing the library to go and do some stuff on a different thread which does something like:
public void DoStuffAsync(AP p)
{
this.Running = true;
this.Cancel = false;
ParameterizedThreadStart threadStart = new ParameterizedThreadStart(DoStuff);
Thread procThread = new Thread(threadStart);
procThread.Start(p);
}
I also have a number of events declared on the interface that the developer can hook into, such as StatusUpdate and ProgressUpdate. I'm currently writing a little test app (in WPF presently although I expect the same behaviour in WinForms) that calls DoStuffAsync() and then updates a progress bar and label.
Unfortunately 1st pass I got an error, the usual thread not being the one which owns the controls. What I'd like to do is remove the need for the user to call Invoke() within the UI side, and for them to simply subscribe to the events and have them work.
So the question, is there a way I can do this is my code when dealing with the event handlers? Currently trigger like so:
public void UpdateProgress(object sender, ProgressEventArgs e)
{
if (handler != null)
{
handler(sender, e);
}
}

Use the AsyncOperationManager instead.
It will do the invoke for you.
(internally it uses the SynchronizationContext as nobugz describes)

You will need a reference to the client's Dispatcher object so you can call Dispatcher.Invoke or Dispatcher.BeginInvoke to marshal the call to the client's UI thread. Do so by letting the client give you the reference you'll need either through the constructor or with a property.
Another way to do it is to store a reference to SynchronizationContext.Current in your class constructor. Use its Send or Post method. That however requires the client to have WPF initialized properly (Application.Run must have been called) and construct your class object from its UI thread.

Related

BackgroundWorker, Methods

So putting the standard background worker crap aside. i was looking into how i can use the background worker a little more than (Worker DoWork { add some commands for it to do })
So this is what i have come up with so far. in this scenario its doing some random WMI stuff
View/ViewModel/Model
The model is called ManagementModel
public void Start(String Args)
{
if (!Worker.IsBusy)
{
//Objectivly here you can spawn an instance of a class and perform a method.. or put the function in the background worker itself depending on what you want the thing to do
ManagementModel BackgroundManagementTask = new ManagementModel();
Worker.RunWorkerAsync(BackgroundManagementTask); //Starts the background worker.
//If you specify the class to shove into the background worker, you need to put the commands of what to do in the DoWork section.
}
}
I have a methods and whatever in the class that was spawned in the Start Method
here is the method for the DoWork
private void Workers_DoWork(object sender, DoWorkEventArgs Args)
{
//This is run on a completly seperate thread, you cannot make any changes to anything outside in this method.
//you instead pass data through the Args.ReportProgress or Args.Result
if (Worker.CancellationPending)
{
Worker.ReportProgress(100, "Cancelled By User");
return;
}
else
{
//if you passed a method here, you will need to convert Args.Arguments back to what ever you passed it in as
ManagementModel Internal = Args.Argument as ManagementModel;
//bunch of stuff in the class that already works
Internal.ComputerName = System.Environment.MachineName;
Internal.Connect();
Internal.ChangeWmiLocation("cimv2",null);
ManagementObjectCollection ResultCollection = Internal.Query("Win32_Process");
ClassProperties ResultProperties = Internal.DisplayProperties;
//now return the results to the program thread
Args.Result = ResultProperties;
//now you need to deal with the data in the WorkerCompleted Event
Worker.ReportProgress(100, "Completed");
Thread.Sleep(60); //this is required at the end of each iteration of function
}
}
So my simple questions are.
is this concept possible, can i initiate an instance of a whole class and throw it into the background worker and have the background worker perform methods and functionality inside the class
if i have to pass data back to the UI. do you think that a Struct would be the best way to go.
How would i let the ViewModel know that the Background worker is completed and update the its exposed properties for the view to update.
or am i way off base ?
Yes, the concept is possible. You can basically have a background worker do and access anything that you can do and access outside of the background worker's methods; the crucial point is that no two threads should be working with objects that haven't been explicitly laid out for that at the same time, which is why for example you should not access your UI from the background worker's working thread (the UI usually constantly being used by internal methods of the UI thread as well).
Whether you use a struct or a class is irrelevant with respect to threads; it is not the data that belongs to a given thread, but the operations. The only difference could be that when passing a struct, a copy of that struct would be created and you could keep working with your struct variable in the background worker thread - but even then, the same is true for a method that invokes callbacks within its own thread before further modifying a local struct/object, so this decision is really not related to threading.
Invoke a UI method that causes the updates to the UI once the background worker has completed its work and make sure it is called on the UI thread. The latter part can be accomplished by various means, depending on the UI toolkit the UI controls may offer a dispatcher object or something like that that allows synchronizing calls with the UI thread.

Run event handlers in another thread (without threads blocking)

I have a class Communicator that works in a background thread receiving data on a TCP port.
The Communicator has an event OnDataReceived which is of a EventHandler<DataReceivedEventArgs> type.
There is another class Consumer that contains a method subscribed to the Communicator.OnDataReceived event.
comm.OnDataReceived += consumer.PresentData;
The Consumer class is created within a Form constructor and then one of its methods is called on another thread. This method is an infinite loop, so it stays in that method during the application execution.
What I'd like to do is for the Communicator.OnDataReceived event to invoke the consumer.PresentData method on consumer's thread.
Is that even nearly possible? And if it is, what kind of mechanisms (sync classes) should I use?
Add this somewhere in your code: (I usually put this in a static helper class called ISynchronizedInvoke so I can call ISynchronizedInvoke.Invoke(...));
public static void Invoke(ISynchronizeInvoke sync, Action action) {
if (!sync.InvokeRequired) {
action();
}
else {
object[] args = new object[] { };
sync.Invoke(action, args);
}
}
Then inside OnDataReceived, you could do:
Invoke(consumer, () => consumer.PresentData());
This invokes 'consumer.PresentData' on 'consumer'.
As for your design issue (consumer references communicator), you could introduce a method inside communicator such as:
class Communicator {
private ISynchronizeInvoke sync;
private Action syncAction;
public void SetSync(ISynchronizeInvoke sync, Action action) {
this.sync = sync;
this.syncAction = action;
}
protected virtual void OnDataReceived(...) {
if (!sync.InvokeRequired) {
syncAction();
}
else {
object[] args = new object[] { };
sync.Invoke(action, args);
}
}
}
This would give you a way to pass in the ISynchronizedInvoke from your consumer class. So you would be creating the ISynchronizedInvoke in the consumer assembly.
class Consumer {
public void Foo() {
communicator.SetSync(this, () => this.PresentData());
}
}
So basically you are creating everything you need to do the invoke, and just passing it in to your communicator. This resolves your necessity to have an instance or reference to consumer in communicator.
Also note that I did not test any of this I am doing this all in theory, but it should work nicely.
Try to use the BackgroundWorker class.
It should be possible. You may create a queue for execution, or look at the Dispatcher object, it's useful (and sometimes mandatory as the only way) to push some methods into the UI Thread, it that helps.
You can get a method to execute on a thread only if the target thread is designed to accept a marshaling operation that transfers the execution of the method from the initiating thread to the target thread.
One way to get this to work is to have your Consumer class implement ISynchronizeInvoke. Then have your Communicator class accept an ISynchronizeInvoke instance that it can use to perform the marshaling operation. Take a look at the System.Timers.Timer class as an example. System.Timers.Timer has the SynchronizingObject property that it can use to marshal the Elapsed event onto the thread hosting the synchronizing object by calling ISynchronizeInvoke.Invoke or ISynchronizeInvoke.BeginInvoke.
The tricky part is how you implement ISynchronizeInvoke on the Consumer class. The worker thread started by that class will have to implement the producer-consumer pattern to be able to process delegates. The BlockingCollection class would make this relatively easy, but there is still quite a learning curve. Give it a shot and post back with a more focused question if you need more help.

How do I call a function in a threadsafe manner

I have been playing around with methods of calling of calling a method safely in threadsafe manner in .net 2.0.
My treeview is populated from a call to a database on a separate thread;
Below is my attempt to use my InvokeFunction method ( shown below) ...it works, but I was hoping that there was a nicer way to write this...any thoughts on this?
InvokeFunction(delegate() { TreeView1.Nodes.Clear(); });
delegate void FunctionDelegate();
private delegate void ThreadSafeProcess(FunctionDelegate func);
private void InvokeFunction(FunctionDelegate func)
{
if (this.InvokeRequired)
{
ThreadSafeProcess d = new ThreadSafeProcess(InvokeFunction);
this.Invoke(d, new object[] { func });
}
else
{
func();
}
}
BackgroundWorker is a cleaner solution in .NET 2.0.
It will create a thread for you and take care of synchronization.
You add BackgroundWorker component to you Form in the design mode.
You subscribe to DoWork event. The method subscribed to this will be execute in a background thread when you call backgroundWorker.RunWorkerAsync() in your UI thread.
When you need to interact with UI thread from your background thread you call backgroundWorker.ReportProgress.
This will trigger ProgressChanged event. ProgressChanged event is always executed in UI thread.
You can use userState parameter of backgroundWorker.ReportProgress to pass any data to UI thread. For example in your case the data that is needed to add new TreeView nodes.
You will actually add new nodes inside of ProgressChanged event handler.
Here is the link to MSDN: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx.
Keep in mind you don't have to use percentProgress parameter of the method ReportProgress method. Although it is convenient when you have a progress bar to reflect background work progress.
You dont have to worry abbout thread safety unless you share some state. Functions always receive their parameters on the stack and stack is local for each thread. So functions are not your problem. Instead focus on the state. "TreeView1" objects is a candidate to worry about.

C# Multi threading- Move objects between threads

i am working with a winforms control that is both a GUI element and also does some internal processing that has not been exposed to the developer. When this component is instantiated it may take between 5 and 15 seconds to become ready so what i want to do is put it on another thread and when its done bring it back to the gui thread and place it on my form. The problem is that this will (and has) cause a cross thread exception.
Normally when i work with worker threads its just with simple data objects i can push back when processing is complete and then use with controls already on the main thread but ive never needed to move an entire control in this fashion.
Does anyone know if this is possible and if so how? If not how does one deal with a problem like this where there is the potential to lock the main gui?
You don't need to lock the GUI, you just need to call invoke:
Controls in Windows Forms are bound to
a specific thread and are not thread
safe. Therefore, if you are calling a
control's method from a different
thread, you must use one of the
control's invoke methods to marshal
the call to the proper thread. This
property can be used to determine if
you must call an invoke method, which
can be useful if you do not know what
thread owns a control. ref
Here is how it looks in code:
public delegate void ComponentReadyDelegate(YourComponent component);
public void LoadComponent(YourComponent component)
{
if (this.InvokeRequired)
{
ComponentReadyDelegate e = new ComponentReadyDelegate(LoadComponent);
this.BeginInvoke(e, new object[]{component});
}
else
{
// The component is used by a UI control
component.DoSomething();
component.GetSomething();
}
}
// From the other thread just initialize the component
// and call the LoadComponent method on the GUI.
component.Initialize(); // 5-15 seconds
yourForm.LoadComponent(component);
Normally calling the LoadComponent from another thread will cause a cross-thread exception, but with the above implementation the method will be invoked on the GUI thread.
InvokeRequired tells you if:
the caller must call an invoke method
when making method calls to the
control because the caller is on a
different thread than the one the
control was created on.
ref
Update:
So if I understand you correctly the control object is created on a thread other than the GUI thread, therefore even if you were able to pass it to the GUI thread you still won't be able to use it without causing a cross-thread exception. The solution would be to create the object on the GUI thread, but initialize it on a separate thread:
public partial class MyForm : Form
{
public delegate void ComponentReadyDelegate(YourComponent component);
private YourComponent _component;
public MyForm()
{
InitializeComponent();
// The componet is created on the same thread as the GUI
_component = new YourComponent();
ThreadPool.QueueUserWorkItem(o =>
{
// The initialization takes 5-10 seconds
// so just initialize the component in separate thread
_component.Initialize();
LoadComponent(_component);
});
}
public void LoadComponent(YourComponent component)
{
if (this.InvokeRequired)
{
ComponentReadyDelegate e = new ComponentReadyDelegate(LoadComponent);
this.BeginInvoke(e, new object[]{component});
}
else
{
// The component is used by a UI control
component.DoSomething();
component.GetSomething();
}
}
}
Without knowing too much about the object. To avoid cross thread exceptions, you can make the initial thread invoke a call (Even if you are calling from a thread).
Copied and pasted from one of my own applications :
private delegate void UpdateStatusBoxDel(string status);
private void UpdateStatusBox(string status)
{
listBoxStats.Items.Add(status);
listBoxStats.SelectedIndex = listBoxStats.Items.Count - 1;
labelSuccessful.Text = SuccessfulSubmits.ToString();
labelFailed.Text = FailedSubmits.ToString();
}
private void UpdateStatusBoxAsync(string status)
{
if(!areWeStopping)
this.BeginInvoke(new UpdateStatusBoxDel(UpdateStatusBox), status);
}
So essentially the threaded task will call the "Async" method. Which will then tell the main form to begininvoke (Actually async itself).
I believe there is probably a shorter way to do all of this, without the need for creating delegates and two different methods. But this way is just ingrained into me. And it's what the Microsoft books teach to you do :p
The BackgroundWorker class is designed for exactly this situation. It will manage the thread for you, and let you start the thread, as well as cancel the thread. The thread can send events back to the GUI thread for status updates, or completion. The event handlers for these status and completion events are in the main GUI thread, and can update your WinForm controls. And the WinForm doesn't get locked. It's everything you need. (And works equally well in WPF and Silverlight, too.)
The control must be created and modified from the UI thread, there's no way around that.
In order to keep the UI responsive while doing long-running initialization, keep the process on a background thread and invoke any control access. The UI should remain responsive, but if it doesn't, you can add some wait time to the background thread. This is an example, using .Net 4 parallel tools: http://www.lovethedot.net/2009/01/parallel-programming-in-net-40-and_30.html
If interaction with the specific control being initialized can't be allowed until initialization finishes, then hide or disable it until complete.

Is it possible to put an event handler on a different thread to the caller?

Lets say I have a component called Tasking (that I cannot modify) which exposes a method “DoTask” that does some possibly lengthy calculations and returns the result in via an event TaskCompleted. Normally this is called in a windows form that the user closes after she gets the results.
In my particular scenario I need to associate some data (a database record) with the data returned in TaskCompleted and use that to update the database record.
I’ve investigated the use of AutoResetEvent to notify when the event is handled. The problem with that is AutoResetEvent.WaitOne() will block and the event handler will never get called. Normally AutoResetEvents is called be a separate thread, so I guess that means that the event handler is on the same thread as the method that calls.
Essentially I want to turn an asynchronous call, where the results are returned via an event, into a synchronous call (ie call DoSyncTask from another class) by blocking until the event is handled and the results placed in a location accessible to both the event handler and the method that called the method that started the async call.
public class SyncTask
{
TaskCompletedEventArgs data;
AutoResetEvent taskDone;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
taskDone.WaitOne(); // but something more like Application.DoEvents(); in WinForms.
taskDone.Reset();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
taskDone.Set(); //or some other mechanism to signal to DoSyncTask that the work is complete.
}
}
In a Windows App the following works correctly.
public class SyncTask
{
TaskCompletedEventArgs data;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
while (data == null) Application.DoEvents();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
}
}
I just need to replicate that behaviour in a window service, where Application.Run isn’t called and the ApplicationContext object isn’t available.
I've had some trouble lately with making asynchronous calls and events at threads and returning them to the main thread.
I used SynchronizationContext to keep track of things. The (pseudo)code below shows what is working for me at the moment.
SynchronizationContext context;
void start()
{
//First store the current context
//to call back to it later
context = SynchronizationContext.Current;
//Start a thread and make it call
//the async method, for example:
Proxy.BeginCodeLookup(aVariable,
new AsyncCallback(LookupResult),
AsyncState);
//Now continue with what you were doing
//and let the lookup finish
}
void LookupResult(IAsyncResult result)
{
//when the async function is finished
//this method is called. It's on
//the same thread as the the caller,
//BeginCodeLookup in this case.
result.AsyncWaitHandle.WaitOne();
var LookupResult= Proxy.EndCodeLookup(result);
//The SynchronizationContext.Send method
//performs a callback to the thread of the
//context, in this case the main thread
context.Send(new SendOrPostCallback(OnLookupCompleted),
result.AsyncState);
}
void OnLookupCompleted(object state)
{
//now this code will be executed on the
//main thread.
}
I hope this helps, as it fixed the problem for me.
Maybe you could get DoSyncTask to start a timer object that checks for the value of your data variable at some appropriate interval. Once data has a value, you could then have another event fire to tell you that data now has a value (and shut the timer off of course).
Pretty ugly hack, but it could work... in theory.
Sorry, that's the best I can come up with half asleep. Time for bed...
I worked out a solution to the async to sync problem, at least using all .NET classes.
Link
It still doesn't work with COM. I suspect because of STA threading. The Event raised by the .NET component that hosts the COM OCX is never handled by my worker thread, so I get a deadlock on WaitOne().
someone else may appreciate the solution though :)
If Task is a WinForms component, it might be very aware of threading issues and Invoke the event handler on the main thread -- which seems to be what you're seeing.
So, it might be that it relies on a message pump happening or something. Application.Run has overloads that are for non-GUI apps. You might consider getting a thread to startup and pump to see if that fixes the issue.
I'd also recommend using Reflector to get a look at the source code of the component to figure out what it's doing.
You've almost got it. You need the DoTask method to run on a different thread so the WaitOne call won't prevent work from being done. Something like this:
Action<int, int> doTaskAction = t.DoTask;
doTaskAction.BeginInvoke(latitude, longitude, cb => doTaskAction.EndInvoke(cb), null);
taskDone.WaitOne();
My comment on Scott W's answer seems a little cryptic after I re-read it. So let me be more explicit:
while( !done )
{
taskDone.WaitOne( 200 );
Application.DoEvents();
}
The WaitOne( 200 ) will cause it to return control to your UI thread 5 times per second (you can adjust this as you wish). The DoEvents() call will flush the windows event queue (the one that handles all windows event handling like painting, etc.). Add two members to your class (one bool flag "done" in this example, and one return data "street" in your example).
That is the simplest way to get what you want done. (I have very similar code in an app of my own, so I know it works)
Your code is almost right... I just changed
t.DoTask(latitude, longitude);
for
new Thread(() => t.DoTask(latitude, longitude)).Start();
TaskCompleted will be executed in the same thread as DoTask does. This should work.

Categories

Resources