 |
|
 |
One very interesting aspect of invoke usage is that of GUI updates, i.e. how you actually update your GUI from a worker thread or invoked delegate.
The problem existed as well in MFC coding. A worker thread can not simply update a GUI element. It could possibly clash with the main GUI thread. In MFC, instead you would post or send a message from the worker thread to the main GUI thread. The GUI thread would then process this message to update the GUI.
In .NET, I don't fully understand how it works, but I think when you have a WinForm based class object, the invoke will run in the thread of the main GUI, so that it can update the GUI element with thread safety. So if you have a worker thread process, say one that is FTPing a large file, and you want a progress bar in your GUI, then the worker thread would periodically invoke a delegate of the progress bar window with a percent complete parameter. The invoked delegate would run in the progressBar window's thread and the GUI update would be made safely.
I'd like to see a response that expands on this topic and explains it with some good examples.
Bob Sandberg
-- modified at 11:05 Monday 26th June, 2006
|
|
|
|
 |
|
 |
I can give you a little info on the subject.
Invoke and InvokeRequired are methods inherited from System.Windows.Forms.Control. That means that you can use them on any Windows Forms control, from a lowly Label all the way up to a Form.
For performance reasons, MS decided not to make instances of controls thread safe (in fact, practically no object instances in the framework are thread safe; all static objects and methods are, however). Controls also need access to the message pump (started by Application.Run()) in order to function properly. So the initial thread that executes when your program runs (check the Main function in program.cs (.NET 2.0)), and that creates the initial form and starts the message pump, is thus referred to as the "UI Thread". It is associated with the message pump and any forms and other controls it creates.
Controls know what thread they were created on, and check to make sure that any calls that manipulate their state are run by this thread. Any attempt to manipulate that state from a thread other than the UI thread will cause the control to throw an InvalidOperationException. To allow for this cross-thread modification of the UI, the Control class offers the InvokeRequired property and the Invoke (and InvokeBegin etc.) method.
When you check InvokeRequired, the control (Form or otherwise) retrieves the window thread process ID of its parent control (this propagates up to the initial parent, I believe). It then compares this ID with the ID of the calling thread. If they do not match, this method returns true (it may return false when the parent control's handle doesn't exist, but that's a rare occurrence that is covered in the documentation). This tells you that the current thread cannot safely manipulate the control. The solution to this problem is to send a message to the UI thread telling it to execute a method for you. This is what Invoke (and its sibilings) does for you.
The Invoke methods essentially (looking at the method in Reflector leads me to keep it simple!) posts a message to the UI thread's message pump, asking it to execute the method passed to Invoke via a delegate (function pointer). When this message is read by the UI thread's message pump, the UI thread executes the method pointed to by the passed delegate, which will be run by the UI thread and is therefore free to modify the Control. Calling Invoke will block the calling thread until the UI thread has completed its task. Calling BeginInvoke will return immediately so that the calling thread can continue processing while the UI thread services the request asynchronously (not calling EndInvoke will not leak resources in this sole case, so it is safe to ignore this part of the APM).
An interesting note--calling Invoke synchronously can cause a bottleneck that will result in your program becoming nonresponsive, if you're not careful. The following code snippet will demonstrate this:
public partial class Form1 : Form { public Form1() { InitializeComponent(); while (!IsHandleCreated) { IntPtr temp = Handle; } ThreadPool.QueueUserWorkItem(Foo); ThreadPool.QueueUserWorkItem(Foo); ThreadPool.QueueUserWorkItem(Foo); } public void Foo(object o) { while (true) { rtb.Invoke(new StringDelegate(UpdateDisplay), new object[] { "Foo!\n" }); } } public void UpdateDisplay(string text) { this.rtb.Text += text; }
public delegate void StringDelegate(string foo); }
To use this code, create a standard WinForm project in C#, add a sigle RichTextBox to the form and call it 'rtb', and then paste this into the codebehind for the form. Since I know that Foo is only called from worker threads, I don't bother to check InvokeRequired. Notice that I call Handle to explicitly cause the form to create its window handle, without which Invoke will not work (this is usually not needed; the fact that I start the worker threads in the constructor necessitates this).
This code demonstrates that worker threads pounding the message pump has the same effect as running the code synchronously via the UI thread. The message pump becomes clogged by calls to run UpdateDisplay, and the worker threads get blocked while waiting for their Invokes to be serviced. In a situation like this, you would want to add Thread.Sleep to the worker threads, indicating a small amount (like 10ms) to give the CPU time to block the worker thread and allow the UI thread to process some of its messages.
|
|
|
|
 |
|
 |
First off, nice article. 
I have a question though, since this article was targeted at the 2.0 framework. How does the Delegate APM compare to using the BackgroundWorker component in the System.ComponentModel namespace? Specifically in regards to performance and expense to create.
I've been using the BackgroundWorker without any problems for a very short while. It seems that it handled most of the complexities async operations internally.
I think this control pretty much yields the same result as using the 'Callback Delegate APM'.
Thank you, Nathen
|
|
|
|
 |
|
 |
That's a very good remark, is there any difference between these two approaches?
-- modified at 5:31 Friday 23rd June, 2006
|
|
|
|
 |
|
 |
By my understanding, both of them, in the end, use the ThreadPool to queue your method for execution. Checking with Reflector, I can see that, in fact, the BackgroundWorker in fact uses BeginInvoke on the delegate you pass to it. The benefit of the BackgroundWorker is that it wraps the whole thing up in a nice package, and provides for a means of communication between the working thread and the calling thread. That's always nice. I'd say definitely stick with the BW if you're comfortable with it.
|
|
|
|
 |
|
 |
The third example: Method CALL Back delegate seems to raise a compiler exception.
the caller: fd.BeginInvoke(AsyncOpComplete, null); does not mesh with the method: private void AsyncOpComplete(IAsyncResult receipt)
Am I missing something? I can't get the exmaple to compile?
Can someone else provide a fix?
-Mike
"In quiet and silence, the truth is made clear."
-- modified at 15:25 Monday 19th June, 2006
|
|
|
|
 |
|
 |
private delegate string StringReturningDelegate(); private void Main() { // create an instance of the delegate pointing to a method // that takes ten seconds to complete StringReturningDelegate fd = new StringReturningDelegate(MethodThatTakes10SecondsToComplete); // Begin invocation of this delegate fd.BeginInvoke(new AsyncCallback(AsyncOpComplete), null); // Do tons of work here. No, seriously. Console.Read(); } /// /// Retrieves the results of MethodThatTakes10SecondsToComplete when called /// asynchronously /// /// The IAsyncResult receipt. private void AsyncOpComplete(IAsyncResult receipt) { // Cast to the actual object so that we can access the delegate AsyncResult result = (AsyncResult)receipt; // retrieve the calling delegate StringReturningDelegate gsld = (StringReturningDelegate)result.AsyncDelegate; // Retrieve our results; this is guaranteed not to block, // as the async op is complete string gresult = gsld.EndInvoke(receipt); // write the result to the console Console.Write(gresult); } // A method that takes 10 seconds, then returns a string private string MethodThatTakes10SecondsToComplete() { Thread.Sleep(10000); return "Done!"; }
=================
Don't forget:
using System.Runtime.Remoting.Messaging; using System.Threading;
|
|
|
|
 |
|
 |
You are probably doing this in VS 2003. If you are, you have to wrap the AsyncOpComplete method in a delegate explicitly. VS2005 and 2.0 do this for you.
|
|
|
|
 |
|
 |
The other posters need to read the code comments a little better.
BTW, nice article. But that picture is disturbing! 
Thanks. KHadden
|
|
|
|
 |
|
 |
The power of Photoshop Image Manipulation as Implemented by Me. I'm kinda counting down the minutes until they pull that image....
|
|
|
|
 |
|
 |
William Sullivan wrote: I'm kinda counting down the minutes until they pull that image....
As long as they don't pull the finger .....
Chris Meech
I am Canadian. [heard in a local bar]
When no one was looking, every single American woman between the ages of 18 and 32 went out and got a tatoo just above their rumpus. [link[^]]
|
|
|
|
 |
|
 |
How is the third method use you describe, of providing a delegate function to be called at the end of the thread, any different from having a thread post a registered windows message and then exit/terminate and have the originating thread handle the registered message?
Additionally there are occassions where it will make sense to effectively 'single thread' a collection of worker threads in order to guarantee dependancies that may exist. And so I've seen code like this AfxStartThread(); WaitForSingeObject(); AfxStartThread(); WaitForSingleObject();
Chris Meech
I am Canadian. [heard in a local bar]
When no one was looking, every single American woman between the ages of 18 and 32 went out and got a tatoo just above their rumpus. [link[^]]
|
|
|
|
 |
|
 |
The difference is that by posting the message you force the UI thread to service the async operation. That negates one of the benefits of asynch ops -- keeping your UI thread responsive to the user. If you need to do more processing prior to updating the UI, you may cause the app to show that lovely (not responding) message that users love oh so much.
I'm not saying that you should use async delegate invocation wherever possible. You have to program for the particular situation. Most of the time synchronous programming is more than sufficient; from there, ThreadPool.QueueUserWorkItem is fine, then comes async delegate invocation, and lastly instances of System.Threading.Thread. Use the tools that work best for your situation.
|
|
|
|
 |
|
 |
Thanks for the response. Good article, too.
Chris Meech
I am Canadian. [heard in a local bar]
When no one was looking, every single American woman between the ages of 18 and 32 went out and got a tatoo just above their rumpus. [link[^]]
|
|
|
|
 |
|
 |
As far as i know, there is only two methods:
- EndInvoke - Callback
And both have different uses. But of course if you use EndInvoke the way you did it, without doing anything else between BeginInvoke and EndInvoke, it has no sense. But you could start a thread, continue doing something else and when ready use the EndInvoke to be sure the other thread has completed its task. And of course, given the threads do not compete over the same resources. If they do, there is no benefit on multithreading, except user interface response.
And of course, "you should always use callback", is not true.
Edgardo Menta
|
|
|
|
 |
|
 |
Edgardo Menta wrote: As far as i know, there is only two methods: - EndInvoke - Callback
As far as I know, I haves no idea what you mean by "there is only two methods." If you are talking about methods of rendezvous, you are mistaken. As the example showed, you can use the IsCompleted property of the IAsyncResult interface to test if the async operation has completed. You can spinlock on this property until it returns true. That is, if you hate everybody who is running on the current machine.
Edgardo Menta wrote: But of course if you use EndInvoke the way you did it, without doing anything else between BeginInvoke and EndInvoke, it has no sense.
Obviously, the examples use the least amount of code to demonstrate the point. I suppose I could have had put the code in a sample application called, oh, I don't know... Nitpick Generator, where after I invoked the delegate I spunlocked on a method that generated random nitpicky things which then printed to the screen until the callback method was run, which at that point would null out the nitpick generator and garbage-collect it... but I'm lazy. I apologize.
Edgardo Menta wrote: And of course, "you should always use callback", is not true.
I could say, "You should never kick somebody in the jellies," which everybody would agree is true; however there are some times when you just have to do it. Just as in there are some times when you just have to call EndInvoke when its possible your calling thread will be blocked. However, if it doesn't matter that your calling thread (be it UI or other) be blocked, then why not just go with a synchronous operation? Async ops, tho they take advantage of multiprocessor machines, do cost in terms of time (to construct) and resources (additional memory pressure). (modified) I guess I was drowning in my own snarkiness to remember that you HAVE TO call EndInvoke for every BeginInvoke, otherwise you leak resources. The sole exception is Control.BeginInvoke, which will not leak resources if you don't call EndInvoke.
-- modified at 8:47 Monday 3rd July, 2006
|
|
|
|
 |
|
 |
I did´nt mean your are lazy. I mean, that your sample shows what u said: EndInvoke is no useful, because it blocks your thread. But only because you do nothing between BeginInvoke and EndInvoke. But false premises, so false conclusions turns true. You could do something else between BeginInvoke and EndInvoke, so when u call EndInvoke, your thread is not blocked. Instead, you decided your thread should wait the new thread to finish (example: the new thread generates some data your thread needs, i mean data dependency, clearly the best one to have between threads if some). So "you should never kick somebody in the jellies" turns to be "you quite often kick somebody in the jellies". The callback method is quite useful when the calling thread is a user interface thread. But if not, maybe you don´t want to use the callback. And, as far as i know if you use IsComplete only to wait it says "true" inside a while, and then call EndInvoke, I don´t see any difference. Not saying that you are lazy, but that your example obscure the point, and contributes to mistaken conclusions. But of course, you don´t have to agree with me.
|
|
|
|
 |
|
 |
Actually, I am lazy, and you are right -- the point of APM is to do multiple things at the same time. So waiting for your async op to finish is pointless.
And, in the end, if you spinlock on IsCompleted until it returns true and then call EndInvoke it produces the same result (blocking your thread's progression) as just calling EndInvoke. But even though they produce the same result they are two different ways to get to that result. For instance, if you wish to show a progress bar (or some other animation) to the user while waiting for an async operation to finish, you could do the following:
class Program { private delegate string DoWorkDelegate(); static void Main(string[] args) { DoWorkDelegate dwd = new DoWorkDelegate(DoWork); IAsyncResult receipt = dwd.BeginInvoke(null, null); Console.WriteLine("Okay, let's figure out the answer"); Console.Write("Working"); while (!receipt.IsCompleted) { Thread.Sleep(500); Console.Write('.'); } Console.WriteLine(); Console.Write(dwd.EndInvoke(receipt)); Console.Read(); } private static string DoWork() { Thread.Sleep(10000); return "The answer is: 43, actually."; } }
As you can see, we are accomplishing something as we spinlock on the IsCompleted property. You cannot do this by calling EndInvoke, since it blocks the calling thread. That's why you can consider them to be two different types of rendezvous techniques. Hope that is more clear than the article. Good programming!
|
|
|
|
 |
|
 |
...In the third example: I believe there should be a delegate - right now there is only the name of a function.
|
|
|
|
 |
|
 |
Petru66 wrote: ...In the third example: I believe there should be a delegate - right now there is only the name of a function.
True, but it works. There are some times that you can pass a method group as a delegate, and some times you cannot. I haven't figured out the rules behind it; I suppose the C# compiler knows what you're trying to do with some specifc types of delegates (events work the same exact way -- someObject.Event += SomeMethod;). This is one of those cases.
|
|
|
|
 |
|
 |
I'm using Microsoft Visual Studio 2003 (7.1.x) and to me it never works if I do not wrap a method into a delegate. I've tried your code, got the expected compile error, corrected and posted my version in a reply to one of the messages above.
|
|
|
|
 |
|
 |
.NET 2.0, VS 2k5 here. That's the problem. I'm amending the article to add this info. Thanks.
|
|
|
|
 |