Re: Want form to show changing data. But it could be closed, or closing, during update.
- From: "Peter Duniho" <NpOeStPeAdM@xxxxxxxxxxxxxxxx>
- Date: Tue, 22 May 2007 13:51:58 -0700
On Tue, 22 May 2007 13:10:55 -0700, Zytan <zytanlithium@xxxxxxxxx> wrote:
Right, so the UI thread handles windows messages for *all forms? This
means all methods are synchronized, so that the close event handler
will never be executed when another method is in mid execution.
Yes, sort of. The above statement needs qualification, as forms that are created in a thread other than the main UI thread are handled in that other thread. But as long as you never create a new form from other than the main UI thread, all of the code in all of the forms that is executed in response to windows messages will be executed on the main UI thread.
For what it's worth, I never have understood the point in using InvokeRequired. I always just invoke. There's no harm in doing so on the form's creating thread, and in most cases I know that I'm calling from another thread anyway. The one possible "downside" is that you need two methods instead of one (the thread-safe one, and the one that actually does work), but frankly I don't like the pattern where a single method does two completely different things depending on some flag anyway (InvokeRequired in this case). And if the work you're doing is reasonably short, it's easy enough to use an anonymous delegate instead (so all the code winds up contained in a single method...obviously you can use an anonymous method with any length code, but I think it's more suitable for blocks of code that are a half-dozen lines or less).
The data gets updated in another thread. This thread will invoke
something to tell the form to update its display with the new data.
So, I will have to call MyDataForm.InvokeRequired, to see if the UI
thread is running the method. If it isn't, I'll make it run it, using
MyDataForm.BeginInvoke.
Uh...okay. Seems like more trouble, but if that's the way you want to do it, it should work. :) See below for reasons you might want to reconsider though...
I use BeginInvoke to avoid deadlocks. (The main form calls Join()
which waits for threads to end, which means a thread cannot be waiting
for the main form with Invoke, or else deadlock).
IMHO, it's generally a bad idea to use Join(). There are certainly some cases where it's just the right thing, but I think for normal inter-thread communications, it's not necessary and results in overly complicated situations. For example:
The data passed has
a lock around the call. This is perfect for Invoke. But, since
BeginInvoke returns immediately, and the caller will unlock, by the
time the UI thread processes the method in the future, it will be
accessing data without a lock. So, I have to make a copy of the
data! And call BeginInvoke with that copy. Whew.
If you were using Invoke(), then you would be assured of synchronizing access to the data via that mechanism. No locking required. Your code would be much simpler, even accounting for whatever different mechanism you require for the main form to be notified of the threads' completion.
Yes, given your use of Join(), using BeginInvoke() is the way around having deadlocks. But you shouldn't have to use Join() in the first place, and so the deadlocks you're fixing by using BeginInvoke() also shouldn't be a problem.
In the form's methods, I can call this.IsDisposed to see if the form
exists or not? The main form caller will have to check if the form is
null or not, as well, before the call.
More complication. Note that the reason you are needing to check whether the form is still around is because you're using BeginInvoke(). Your use of BeginInvoke() also introduces a somewhat odd situation in that none of the BeginInvoke() calls that you've made will actually execute until your main thread leaves the Join() call. So not only does your form not get a chance to do any updating for user feedback, you create a situation where all of the possible feedback gets done all at once, regardless of the intervals between when the processing has been completed, and all of that feedback could conceiveably be executed *after* the form has been disposed.
If, instead, you used Invoke(), providing a different mechanism for the main form to know the threads are done, the user would get timely feedback as each thread finishes. In addition, if you provide a mechanism for the threads to be interrupted (ie the main thread signals to them to exit without finishing), then you could have a way for the user to just cancel the processing altogether (which would be useful when the user closes the form, or exits the application, or pushes a button that says "Stop Processing", or whatever). You would want to be careful to not assume any given thread actually got the signal; if you set it just as the thread was exiting or updating the form, for example, it would be moot at that point. But again, since you'd have a mechanism for each thread to notify the main form about completion, this should not be a problem.
To avoid the main form from caring if this form exists, I could call a
static method. It will call InvokeRequired (to see if it's in the UI
thread), then BeginInvoke (to force it to be in the UI thread), and
only at this time, I can check a local variable that says if the form
exists or not (which is set on load and close). I cannot check it
before, because BeginInvoke delays the actual method execution.
Interesting. More complication. :) Note that all of this complication basically stems from your use of Join(), which is requiring the use of asynchronous invokes on the main form, which is causing all of these synchronization issues. Stop using Join(), and all of the sudden everything can be synchronous again, and the issues go away. :)
Ok, thanks for the ideas, Nicholas
For what it's worth, I think you read a lot into Nicholas' reply that wasn't necessarily there. He answered your specific question, and gave you good advice regarding how to deal with the potential for the form disappearing before some thread tries to access it in some way. But I didn't see anything in his reply that said it was a good idea to get into that situation if you can avoid it. :)
Pete
.
- Follow-Ups:
- References:
- Want form to show changing data. But it could be closed, or closing, during update.
- From: Zytan
- Re: Want form to show changing data. But it could be closed, or closing, during update.
- From: Nicholas Paldino [.NET/C# MVP]
- Re: Want form to show changing data. But it could be closed, or closing, during update.
- From: Zytan
- Want form to show changing data. But it could be closed, or closing, during update.
- Prev by Date: Where is the information stored about the exact position of e.g. a button on a form ?
- Next by Date: Re: How to call Form2.cs from Form1.cs in modal and in non-modal style ?
- Previous by thread: Re: Want form to show changing data. But it could be closed, or closing, during update.
- Next by thread: Re: Want form to show changing data. But it could be closed, or closing, during update.
- Index(es):