public void RefreshData()
{
// this is called on UI thread
List<ds> dataSource;
GetDsDelegate caller = GetDs;
caller.BeginInvoke(out dataSource, RefreshCallback, null);
}
private void RefreshCallback(IAsyncResult ar)
{
// this is called on worker thread
try
{
var result = (AsyncResult)ar;
var caller = (GetDsDelegate)result.AsyncDelegate;
List<ds> dataSource;
var success = caller.EndInvoke(out dataSource, ar);
if (success)
{
BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource);
}
}
catch
{
// NOTE: It's possible for this form to close after RefreshData is called
// but before GetDs returns thus the SetGridDataSource method no longer exists.
// Not catching this error causes the entire application to terminate.
}
private void SetGridDataSource(List<ds> dataSource)
{
// this is called on UI thread
dataGrid.DataSource = dataSource;
}
RefreshData, RefreshCallback, and SetGridDataSource are all methods of a windows Form class. Calling RefreshData invokes the external method GetDs using the GetDsDelegate delegate. When GetDs completes, it calls RefreshCallback (now on a separate thread). Finally, SetGridDataSource is invoked to complete the update.
All this works fine unless GetDs is delayed and the form closes. Then when GetDs completes and calls RefreshCallback, SetGridDataSource no longer exists.
Is there a better way of handling this condition other then the shown try/catch block? I’d prefer to prevent the error rather than ignore it. Is there a better pattern to use?
EDIT
As I look that the error, it’s obvious to change if (success) to if (success && IsHandleCreated) to prevent it, but it still seems like I’m doing something wrong, or at least awkward. I could also replace the second BeginInvoke with just Invoke so EndInvoke is unnecessary. I like the idea of moving the logic away from the form, but I don't see how the result would change. I would think a BackgroundWorker would also have the same issue; that being the callback is no longer accessible. I suppose an event could be raised with the result, but that seems a little abstract. Could you please elaborate a little more or provide an example.
The method does exist. The fact the form was closed does not change the class or its methods. If you post the exact exception you're getting, it can help someone offer a more accurate help.
I'm guessing you got an ObjectDisposedException when you tried to do something on the form or one of its control after it has been closed.
If that's the case you just have to enhance your logic and check if the form has been closed or disposed before calling SetGridDataSource.
That said, there seem to be some issues with your design.
You're calling SetGridDataSource from the thread pool, but it probably should called from the UI thread.
Your'e not chaining the asynchronous calls correctly. And specifically, you're not calling EndInvoke on the second BeginInvoke.
A nice way that can help you get the threading right is to use something like the BackgroundWorker instead of chaining BeginInvoke calls.
Consider moving the business logic (including the threading and asynchronity logic) away from the UI layer and the form.
It's a very bad idea to do a catch without an exception type, and handle any thrown exception by ignoring it without rethrowing.
By the way, instead of doing this:
BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource);
you can do the following, which I think is more readable:
BeginInvoke(SetGridDataSource, dataSource);
Related
I have a UserControl with a TreeView control called mTreeView on it. I can get data updates from multiple different threads, and these cause the TreeView to be updated. To do this, I've devised the following pattern:
all data update event handlers must acquire a lock and then check for InvokeRequired; if so, do the work by calling Invoke. Here's the relevant code:
public partial class TreeViewControl : UserControl
{
object mLock = new object();
void LockAndInvoke(Control c, Action a)
{
lock (mLock)
{
if (c.InvokeRequired)
{
c.Invoke(a);
}
else
{
a();
}
}
}
public void DataChanged(object sender, NewDataEventArgs e)
{
LockAndInvoke(mTreeView, () =>
{
// get the data
mTreeView.BeginUpdate();
// perform update
mTreeView.EndUpdate();
});
}
}
My problem is, sometimes, upon startup, I will get an InvalidOperationException on mTreeView.BeginUpdate(), saying mTreeView is being updated from a thread different than the one it was created. I go back in the call stack to my LockAndInvoke, and lo and behold, c.InvokeRequired is true but the else branch was taken! It's as if InvokeRequired had been set to true on a different thread after the else branch was taken.
Is there anything wrong with my approach, and what can I do to prevent this?
EDIT: my colleague tells me that the problem is that InvokeRequired is false until the control is created, so this is why it happens on startup. He's not sure what to do about it though. Any ideas?
It is a standard threading race. You are starting the thread too soon, before the TreeView is created. So your code sees InvokeRequired as false and fails when a split second later the native control gets created. Fix this by only starting the thread when the form's Load event fires, the first event that guarantees that all the control handles are valid.
Some mis-conceptions in the code btw. Using lock is unnecessary, both InvokeRequired and Begin/Invoke are thread-safe. And InvokeRequired is an anti-pattern. You almost always know that the method is going to be called by a worker thread. So use InvokeRequired only to throw an exception when it is false. Which would have allowed diagnosing this problem early.
When you marshal back to the UI thread, it's one thread--it can do only one thing at at time. You don't need any locks when you call Invoke.
The problem with Invoke is that it blocks the calling thread. That calling thread usually doesn't care about what get's completed on the UI thread. In that case I recommend using BeginInvoke to marshal the action back to the UI thread asynchronously. There are circumstances where the background thread can be blocked on Invoke while the UI thread can be waiting for the background thread to complete something and you end up with a deadlock: For example:
private bool b;
public void EventHandler(object sender, EventArgs e)
{
while(b) Thread.Sleep(1); // give up time to any other waiting threads
if(InvokeRequired)
{
b = true;
Invoke((MethodInvoker)(()=>EventHandler(sender, e)), null);
b = false;
}
}
... the above will deadlock on the while loop while because Invoke won't return until the call to EventHandler returns and EventHandler won't return until b is false...
Note my use of a bool to stop certain sections of code from running. This is very similar to lock. So, yes, you can end up having a deadlock by using lock.
Simply do this:
public void DataChanged(object sender, NewDataEventArgs e)
{
if(InvokeRequired)
{
BeginInvoke((MethodInvoker)(()=>DataChanged(sender, e)), null);
return;
}
// get the data
mTreeView.BeginUpdate();
// perform update
mTreeView.EndUpdate();
}
This simply re-invokes the DataChanged method asynchronously on the UI thread.
The pattern as you have shown it above looks 100% fine to me (albeit with some extra unnecessary locking, however I can't see how this would cause the problem you have described).
As David W points out, the only difference between what you are doing and this extension method is that you directly access mTreeView on the UI thread instead of passing it in as an argument to your action, however this will only make a difference if the value of mTreeView changes, and in any case you would have to try fairly hard to get this to cause the problem you have described.
Which means that the problem must be something else.
The only thing that I can think of is that you may have created mTreeView on a thread other than the UI thread - if this is the case then accessing the tree view will be 100% safe, however if you try and add that tree view to a form which was created on a different thread then it will go bang with an exception similar to the one that you describe.
I created a multithreading C# COM-Assembly, I used it from VB6.
The C#-COM can fire events from multiple threads, I created an invisible From-object and use this to synchronize all events before raise them.
if (myForm.InvokeRequired() )
{
delOnMessage myDelegate = new delOnMessage(Message_received);
myForm.Invoke(myDelegate, new object[] { null, null });
}
else
{
RaiseMyEvent();
}
But if the VB6-Code is inside of an event handler and calls some methods of the COM-Object, this can produce a new event.
Private Sub m_SomeClass_SomeEvent(obj As Variant)
COMobject.SendAnAnswer() ' This produces a new event
End Sub
In that case a part of the event-system stops working, suprisingly the Main VB6 Applikation still works.
EDIT: More detailed
If the C#-COM received a Message (from CAN-Bus-Thread) it creates an event, in some cases the VB6 calls a C#-COM method which creates an event, this event is reached the VB6 too.
But then the CAN-Bus-Thread seems to be blocked, as no more messages are received (till program restart).
But other events can occur.
The CAN-Bus-Thread is an endless loop to receive a message and fire an event.
I have two questions:
Is my way of synchronizing correct?
Is it possible without modifying the VB6-code to get it working?
I created an invisible From-object
That sounds like trouble. Using InvokeRequired is a dangerous anti-pattern. It is especially lethal with VB6, its runtime has badly broken thread handling. You know that the code is being called from a worker thread, use InvokeRequired only to verify that the form you use to synchronize is in the proper state to do so correctly:
if (!myForm.InvokeRequired()) {
throw new InvalidOperationException("Synchronization window not created");
}
delOnMessage myDelegate = new delOnMessage(FireMessageReceivedEvent);
myForm.BeginInvoke(myDelegate, new object[] { null, null });
Odds are good that this exception will throw, creating an invisible form is not that easy. You can force the form's Handle property to be created by reading its Handle property. Or by overriding its SetVisibleCore() method to keep the form invisible:
protected override void SetVisibleCore(bool value) {
if (!this.IsHandleCreated) {
this.CreateHandle();
value = false;
}
base.SetVisibleCore(value);
}
It is however very important that you call this form's Show() method on the main thread. It still won't work correctly if you create the form in your worker thread. There's no easy way to check for this in your code. Use the debugger and the Debug + Windows + Threads window to verify this.
Last but not least, do favor BeginInvoke() instead of Invoke(). This has much smaller odds of creating deadlock. This can cause problems by itself however, your worker thread may need to be throttled to prevent it flooding the main thread with invoke requests.
Depending on the nature of the event, it may be sufficient simply to switch from Invoke to BeginInvoke, so that it is offloaded to the message-queue (without blocking, so no deadlock). It is convenient that Control.BeginInvoke (unlike Delegate.BeginInvoke) does not require you to call EndInvoke, so you can use this in a fire-and-forget way.
I might be tempted to cut out some extra work, though:
myForm.BeginInvoke((MethodInvoker)RaiseMyEvent);
(i.e. jump direct to RaiseMyEvent)
I get the following exception thrown:
Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
This is my code:
if (InvokeRequired)
{
BeginInvoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount);
}
else
Invoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount);
I found pages about this topic on this site but I don't know what is wrong.
The difference between Invoke and BeginInvoke is that the former is synchronous (waits for completion) while the later is asynchronous (sort of fire-and-forget). However, both work by posting a message to the UI message loop which will cause the delegate to be executed when it gets to that message.
The InvokeRequired property determines whether you need to Invoke at all or if it is already on the correct thread, not whether you want synchronous or asynchronous calling. If InvokeRequired is false you are (in theory) already running on the UI thread and can simply perform synchronous actions directly (or still BeginInvoke if you need to fire them off asynchronously). This also means you can't use Invoke if InvokeRequired is false, because there's no way for the message loop on the current thread to continue. So that's one big problem with your code above, but not necessarily the error you're reporting. You can actually use BeginInvoke in either case, if you watch out for recursive invocation, and so on.
However, you can't use either one without a window handle. If the Form/Control has been instantiated but not initialized (ie. before it is first shown) it may not have a handle yet. And the handle gets cleared by Dispose(), such as after the Form is closed. In either case InvokeRequired will return false because it is not possible to invoke without a handle. You can check IsDisposed, and there is also a property IsHandleCreated which more specifically tests if the handle exists. Usually, if IsDisposed is true (or if IsHandleCreated is false) you want to punt into a special case such as simply dropping the action as not applicable.
So, the code you want is probably more like:
if (IsHandleCreated)
{
// Always asynchronous, even on the UI thread already. (Don't let it loop back here!)
BeginInvoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount);
return; // Fired-off asynchronously; let the current thread continue.
// WriteToForm will be called on the UI thread at some point in the near future.
}
else
{
// Handle the error case, or do nothing.
}
Or maybe:
if (IsHandleCreated)
{
// Always synchronous. (But you must watch out for cross-threading deadlocks!)
if (InvokeRequired)
Invoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount);
else
WriteToForm(finished, numCount); // Call the method (or delegate) directly.
// Execution continues from here only once WriteToForm has completed and returned.
}
else
{
// Handle the error case, or do nothing.
}
This will typically happen in multithreaded scenarios where some external source (maybe a NetworkStream) pushes data to a form before the form has properly initialized.
The message can also appear after a Form is disposed.
You can check IsHandleCreated to see if a form is already created, but you need to put everything in proper error handling as the Invoke statement can throw an exception if you try to update your form while your application is closing.
here is my answer
Let's say you want to write"Hello World" to a text box.
Then IF you use "Ishandlecreated" then your operation will not happen if handlers are not yet created. So You must force itself to CreateHandlers if not yet created.
Here is my code
if (!IsHandleCreated)
this.CreateControl();
this.Invoke((MethodInvoker)delegate
{
cmbEmail.Text = null;
});
Assuming the form is not disposed but not yet fully initialized just put var X = this.Handle; before that if statement... by this the instance of the respective form is meant.
see http://msdn.microsoft.com/en-us/library/system.windows.forms.control.handle.aspx .
If you're going to use a control from another thread before showing the control or doing other things with the control, consider forcing the creation of its handle within the constructor. This is done using the CreateHandle function. In a multi-threaded project, where the "controller" logic isn't in a WinForm, this function is instrumental for avoiding these kinds of errors.
What about this :
public static bool SafeInvoke( this Control control, MethodInvoker method )
{
if( control != null && ! control.IsDisposed && control.IsHandleCreated && control.FindForm().IsHandleCreated )
{
if( control.InvokeRequired )
{
control.Invoke( method );
}
else
{
method();
}
return true;
}
return false;
}
Use it like that :
this.label.SafeInvoke(new MethodInvoker( () => { this.label.Text = yourText; }));
You are probably calling this in the constructor of the form, at that point the underlying system window handle does not exist yet.
Add this before you call your invoke method:
while (!this.IsHandleCreated)
System.Threading.Thread.Sleep(100)
This solution worked for me.
Anytime the beginner asks something like: How to update the GUI from another thread in C#?, the answer is pretty straight:
if (foo.InvokeRequired)
{
foo.BeginInvoke(...)
} else {
...
}
But is it really good to use it? Right after non-GUI thread executes foo.InvokeRequired the state of foo can change. For example, if we close form right after foo.InvokeRequired, but before foo.BeginInvoke, calling foo.BeginInvoke will lead to InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created. This wouldn't happen if we close the form before calling InvokeRequired, because it would be false even when called from non-GUI thread.
Another example: Let's say foo is a TextBox. If you close form, and after that non-GUI thread executes foo.InvokeRequired (which is false, because form is closed) and foo.AppendText it will lead to ObjectDisposedException.
In contrast, in my opinion using WindowsFormsSynchronizationContext is much easier - posting callback by using Post will occur only if thread still exists, and synchronous calls using Send throws InvalidAsynchronousStateException if thread not exists anymore.
Isn't using WindowsFormsSynchronizationContext just easier? Am I missing something? Why should I use InvokeRequired-BeginInvoke pattern if it's not really thread safe? What do you think is better?
WindowsFormsSynchronizationContext works by attaching itself to a special control that is bound to the thread where the context is created.
So
if (foo.InvokeRequired)
{
foo.BeginInvoke(...)
} else {
...
}
Can be replaced with a safer version :
context.Post(delegate
{
if (foo.IsDisposed) return;
...
});
Assuming that context is a WindowsFormsSynchronizationContext created on the same UI thread that foo was.
This version avoid the problem you evoke :
Right after non-GUI thread executes foo.InvokeRequired the state of foo can change. For example, if we close form right after foo.InvokeRequired, but before foo.BeginInvoke, calling foo.BeginInvoke will lead to InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created. This wouldn't happen if we close the form before calling InvokeRequired, because it would be false even when called from non-GUI thread.
Beware of some special cases with WindowsFormsSynchronizationContext.Post if you play with multiple message loops or multiple UI threads :
WindowsFormsSynchronizationContext.Post will execute the delegate only if there still is a message pump on the thread where it was created. If there isn't nothing happens and no exception is raised.Also if another message pump is later attached to the thread (Via a second call to Application.Run for example) the delegate will execute (It's due to the fact that the system maintain a message queue per thread without any knowledge about the fact that someone is pumping message from it or not)
WindowsFormsSynchronizationContext.Send will throw InvalidAsynchronousStateException if the thread it's bound to isn't alive anymore. But if the thread it's bound to is alive and doesn't run a message loop it won't be executed immediately but will still be placed on the message queue and executed if Application.Run is executed again.
None of these cases should execute code unexpectedly if IsDisposed is called on a control that is automatically disposed (Like the main form) as the delegate will immediately exit even if it's executed at an unexpected time.
The dangerous case is calling WindowsFormsSynchronizationContext.Send and considering that the code will be executed: It might not, and there is now way to know if it did anything.
My conclusion would be that WindowsFormsSynchronizationContext is a better solution as long as it's correctly used.
It can create sublte problems in complex cases but common GUI applications with one message loop that live as long as the application itself will always be fine.
Who said InvokeRequired / Control.BeginInvoke is preferred? If you ask me, in most cases it's an anti pattern for the exact reasons you mentioned. The question you linked to has many answers, and some actually do suggest using the synchronization context (including mine).
While it's true that any given control could be disposed by the time you're trying to access it from the posted delegate, that's easily solved using Control.IsDisposed (as your delegate is executing on the UI thread so nothing can dispose controls while it's running):
public partial class MyForm : Form
{
private readonly SynchronizationContext _context;
public MyForm()
{
_context = SynchronizationContext.Current
//...
}
private MethodOnOtherThread()
{
//...
_context.Post(status =>
{
// I think it's enough to check the form's IsDisposed
// But if you want to be extra paranoid you can test someLabel.IsDisposed
if (!IsDisposed) {someLabel.Text = newText;}
},null);
}
}
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.