locked
What happen actually when control.BeginInvoke is called? RRS feed

  • Question

  • Hello,

    Control.BeginInvoke(Delegate) : Executes the specified delegate "asynchronously on the thread" that the control's underlying handle was created on. The delegate is called asynchronously. You can call this method from any thread, "even the thread that owns the control's handle."

    Referring the above texts in bold, what will happen actually if we call BeginInvoke method of any control in the Main Thread ( which is busy executing some other tasks)?

    Will there be two threads?

    Or this call to BeginInvoke will wait for Main thread to complete its executing task? if so, then UI may go into nonresponding state if the executing task of Main Thread is quite  time consuming.

    Wednesday, September 1, 2010 12:00 PM

Answers

  • You seem to be not understanding how messages work.

    Let's say you need you cousin from another city to do something. So you're sending mail with instructions. All you need to do is to put envelope into mail box and that's it. You do not need to wait for your cousin to be free or anything. Same with threads: worker thread sends a message and continues, whatever main thread is doing is not relevant.

    OK, you put this main into mailbox. Will your cousin immediately jump to the mail box to retrieve mail from you to execute your task leaving whatever s(he) was doing incomplete? Probably not as cousin would not even know there's a message until s(he) has time to check the mail box. Same here: worker thread sends a message, UI thread checks messages next time it's free. If it was doing something it would have to complete that before it can check for messages.

    It would not keep UI in "responding state". This is just the case of executing code on the main thread - until this code is completed UI would be blocked regardless of how it was started (e.g. from event handler or via Invoke). Whatever code you're executing on UI thread it should never block execution for longer than ~100 ms. Generally you should do all the work on the worker thread and just update UI from BeginInvoke(), e.g. to display results of your calculations.

    In your example DoSomeCalculations() should be done on the worker thread and not UI thread. Code then can look something like this:

    //Presuming there is a textbox on the form.
    
    public class cSample
    {

    public delegate void InvokeDelegate();

    public void InvokeMethod()
    {
    textBox1.Text = "Executed the given delegate" ;
    }
    // This method will be called when the thread is started.
    public void DoWork()
    {

    DoSomeCalculation();

    while
    (true )
    {
    //infinite loop just to assume that this is quite a time consuming task
    }


    textBox1.BeginInvoke(new InvokeDelegate(InvokeMethod));
    }

    public static int Main()
    {
    // Create the thread object. This does not start the thread.
    Thread workerThread = new Thread(DoWork);

    // Start the worker thread.
    workerThread.Start();

    // Probably would need a call to Application.Start();

    return 0;
    }
    public void DoSomeCalculation()
    {
    //some very huge calculation
    }

    }

    This posting is provided "AS IS" with no warranties, and confers no rights.
    • Marked as answer by ost1 Tuesday, September 7, 2010 8:44 AM
    Saturday, September 4, 2010 10:03 AM
  • Essentially as you execute BegingInvoke(), message is sent to the main window which asks for execution of a certain delegate. At some point message is retrieved and delegate is executed on the UI thread.

    BeginInvoke will not wait (unlike Invoke), it would send a message and continue.

    If you're calling BeginInvoke from the main thread it (main tread) can not possibly be busy executing some other tasks because it is executing BeginInvoke at this very moment.

    Since delegate is executed on UI thread it is possible to block UI from it - just like in any other code which is executed in UL thread.


    This posting is provided "AS IS" with no warranties, and confers no rights.
    • Marked as answer by warrentang Monday, September 6, 2010 3:02 AM
    Wednesday, September 1, 2010 6:01 PM

All replies

  • Is the "main thread" STAThread (Single Threaded Apartment Thread), that is, the UI?  I presume so, because of the wording of your question.  As you might imagine the UI is STAThread'ed, and as this implies, there is just a single thread for the UI.  Thus, the delegate called by Invoke will execute in this same thread context, generally when other "things" are finished, but without guarantee about the exact timing. 

    And, yes, it is possible for the UI to become unresponsive, if the delegate code takes a long time to execute.  The same it true for other code that might be called from the UI, if that code also takes a long time to execute without calling the UI message pump.  Application.DoEvents() may or may not provide some help here.

    So, at the end of the day, what you want to do is to minimize any processing that is done in the delegate (maximizing preprocessing in the background thread that calls the delegate).  Still, it is possible to run into processing constraints.  We are dealing with single-core processors that have more limited capability than their desktop counterparts.

    Dick


    Dick Grier. Author of Visual Basic Programmer's Guide to Serial Communications 4. See www.hardandsoftware.net.
    Wednesday, September 1, 2010 4:41 PM
  • Essentially as you execute BegingInvoke(), message is sent to the main window which asks for execution of a certain delegate. At some point message is retrieved and delegate is executed on the UI thread.

    BeginInvoke will not wait (unlike Invoke), it would send a message and continue.

    If you're calling BeginInvoke from the main thread it (main tread) can not possibly be busy executing some other tasks because it is executing BeginInvoke at this very moment.

    Since delegate is executed on UI thread it is possible to block UI from it - just like in any other code which is executed in UL thread.


    This posting is provided "AS IS" with no warranties, and confers no rights.
    • Marked as answer by warrentang Monday, September 6, 2010 3:02 AM
    Wednesday, September 1, 2010 6:01 PM
  • Hi Ilya,

    Thanks for your helpful reply.

    I still have got one doubt.

    Consider the following sample code.

    Here Main thread starts another thread "workerThread". This worker thread calls BeginInvoke of textbox1, while Main Thread is still in DoSomeCalculation method block (assuming it is doing some very time consuming calculation). As the BeginInvoke call has to be an asynchronous call on the Main Thread and "BeginInvoke will not wait" (as per your last reply), my doubt is...what will happen here?

    1)Will Main Thread immediately jump to InvokeMethod(), leaving its incomplete calculation of DoSomeCalculation()....because "BeginInvoke will not wait"?

    2)How will Main Thread keep the UI in responding state if it is busy in time consuming task of InvokeMethod().......because BeginInvoke call has to be an asynchronous call ?

    Please help me to get this concept clear?

    //Presuming there is a textbox on the form.
    public class cSample
    {
    
     public delegate void InvokeDelegate();
    
     public void InvokeMethod()
     {
      textBox1.Text = "Executed the given delegate";
      while(true)
      {
       //infinite loop just to assume that this is quite a time consuming task
      }
     }
     // This method will be called when the thread is started.
     public void DoWork()
     {
      textBox1.BeginInvoke(new InvokeDelegate(InvokeMethod));
     }
    
     public static int Main()
     {
      // Create the thread object. This does not start the thread.
      Thread workerThread = new Thread(DoWork);
    
      // Start the worker thread.
      workerThread.Start();
      DoSomeCalculation();
      return 0;
     }
     public void DoSomeCalculation()
     {
      //some very huge calculation
     }
    
    }
    

    Thanks in advance,

    Piush

    Friday, September 3, 2010 10:17 AM
  • You seem to be not understanding how messages work.

    Let's say you need you cousin from another city to do something. So you're sending mail with instructions. All you need to do is to put envelope into mail box and that's it. You do not need to wait for your cousin to be free or anything. Same with threads: worker thread sends a message and continues, whatever main thread is doing is not relevant.

    OK, you put this main into mailbox. Will your cousin immediately jump to the mail box to retrieve mail from you to execute your task leaving whatever s(he) was doing incomplete? Probably not as cousin would not even know there's a message until s(he) has time to check the mail box. Same here: worker thread sends a message, UI thread checks messages next time it's free. If it was doing something it would have to complete that before it can check for messages.

    It would not keep UI in "responding state". This is just the case of executing code on the main thread - until this code is completed UI would be blocked regardless of how it was started (e.g. from event handler or via Invoke). Whatever code you're executing on UI thread it should never block execution for longer than ~100 ms. Generally you should do all the work on the worker thread and just update UI from BeginInvoke(), e.g. to display results of your calculations.

    In your example DoSomeCalculations() should be done on the worker thread and not UI thread. Code then can look something like this:

    //Presuming there is a textbox on the form.
    
    public class cSample
    {

    public delegate void InvokeDelegate();

    public void InvokeMethod()
    {
    textBox1.Text = "Executed the given delegate" ;
    }
    // This method will be called when the thread is started.
    public void DoWork()
    {

    DoSomeCalculation();

    while
    (true )
    {
    //infinite loop just to assume that this is quite a time consuming task
    }


    textBox1.BeginInvoke(new InvokeDelegate(InvokeMethod));
    }

    public static int Main()
    {
    // Create the thread object. This does not start the thread.
    Thread workerThread = new Thread(DoWork);

    // Start the worker thread.
    workerThread.Start();

    // Probably would need a call to Application.Start();

    return 0;
    }
    public void DoSomeCalculation()
    {
    //some very huge calculation
    }

    }

    This posting is provided "AS IS" with no warranties, and confers no rights.
    • Marked as answer by ost1 Tuesday, September 7, 2010 8:44 AM
    Saturday, September 4, 2010 10:03 AM
  • Hi Ilya, Thanks a lottttt :)  

    Piush

    Tuesday, September 7, 2010 8:46 AM