Invoke vs BeginInvoke

Now that 2.0 (with its detection of accessing control properties from an incorrect thread) has become main stream there are numerous people realizing that they had many bugs in their 1.1 code.

I could write up a bunch of information about why you need to do this but I think  and others already do a great job of this. I am instead going to talk about how things work (that you probably don't care about).

Once upon a time in a land far away there were two API calls, SendMessage and PostMessage. They were fraternal twins, although they looked the same their personalities were quite different. In order to understand the differences we have to go back to the time when they ruled the desktop. Extremely outdated but useful article: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/msdn_winthr.asp

From all the reading I have done I got quite worried about using invoke. SendMessage can have many problems if the message pump isn't responding.. it will block forever.

PostMessage also has problems but they are generally more subtle

Thread 1 calls invoke Thread 2 is joining to Thread 1 Thread 1 is blocking on 2 ... thread 2 is blocking on 1...

If you read around.. you will have people tell you that in.NET Invoke uses SendMessage and that BeginInvoke uses PostMessage

http://blogs.msdn.com/larryosterman/archive/2005/03/22/400583.aspx

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dntake/html/yctiwy_multithreadingandui.asp

Are a few that came up in searching.

This does not seem to be true (I may be wrong but fifteen minutes of research with reflector seems to agree).. Both Control.Invoke and Control.BeginInvoke use PostMessage. Here is the relevant reflectorred code.

First we have InvokeRequired.. this does exactly what we would think it to do.

            int num2 = SafeNativeMethods.GetWindowThreadProcessId(ref1, out num1);             int num3 = SafeNativeMethods.GetCurrentThreadId;             return (num2!= num3);

Here is MarshaledInvoke (which is called by both Invoke and BeginInvoke). SOme code is taken out...

      bool flag1 = false;       if ((SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, this.Handle), out num1) == SafeNativeMethods.GetCurrentThreadId) && synchronous)       {             flag1 = true;       }

      if (flag1)       {             this.InvokeMarshaledCallbacks;       }       else       {             UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle), Control.threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);       }       if (!synchronous)       {             return entry1;       }       if (!entry1.IsCompleted)       {             this.WaitForWaitHandle(entry1.AsyncWaitHandle);       }       if (entry1.exception!= null)       {             throw entry1.exception;       }       return entry1.retVal;

You will notice that the same check is done as in Control.InvokeRequired to set flag1, if an invoke is required it will in fact always use PostMessage (not SendMessage).

In general Control.Invoke should never be used. The asynchronous PostMessage runs the risk of thread deadlocks.. If you must be synchronous atleast try to detect a deadlock as opposed to trashing your thread (by using a timeout in your wait).

AsyncWaitHandle.WaitOne(Timeout, false) http://msdn2.microsoft.com/en-US/library/kzy257t0.aspx

A good strategy for avoiding deadlocks is to pass a clone of the object instead of the object itself. By passing a copy of our objects we can minimize our chances of deadlock. IanG had some good things to say about this here http://interact-sw.co.uk/iangblog/2004/04/20/whatlocks

For those who use SendMessageDirectly.. just keep in mind all the problems that can come up:)

Odd google search of the day.. http://www.google.com/search?hl=en&lr=&q=google+hit+history note the #1 result  note that the only search term found is the word history:)

This article is part of the GWB Archives. Original Author: Greg Young

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.