views:

58

answers:

3

I have had recently one of those really bad interviews, where they play good cop/bad cop with you. Whatever I replied wasn't good enough for one of them and my confidence was shrinking minute by minute. His final question that really confused me was the following:

if a control would need InvokeRequired would there be a difference in doing .Invoke or .BeginInvoke?

Let me show you an example, how I understand it:

public delegate string WorkLongDelegate(int i);

var del = new WorkLongDelegate(WorkLong);
var callback = new AsyncCallback(CallBack);
del.BeginInvoke(3000, callback, del);

public string WorkLong(int i)
{
      Thread.Sleep(i);
      return (string.Format("Work was done within {0} seconds.", i));            
}

private void CallBack(IAsyncResult ar)
{
    var del = (WorkLongDelegate) ar.AsyncState;
    SetText2(del.EndInvoke(ar));
}

private void SetText2(string s)
{
   if(InvokeRequired)
   {
       // What is the difference between BeginInvoke and Invoke in below?
       BeginInvoke(new MethodInvoker(() => textBox1.Text = s)); 
   }
   else
   {
       textBox1.Text = s;
   }
}

I mentioned that BeginInvoke would do it asynchronously while Invoke would be halting the UI thread until its executed. But that wasn't good enough. Nonetheless, I don't understand the performance implication in here if I used an Invoke instead. May someone please enlighten me?

A: 

Naturally, if using the asnyc version, your background thread can continue immediately, without waiting for the context switch.

Usually, this should be faster (for the background thread), from what I do unterstand.

Uwe Keim
+5  A: 

Invoke doesn't halt the UI thread. It blocks the calling thread from continuing until the UI thread has completed.

So really, the question is whether you want the background operation to continue before the UI has finished updating. Usually I believe this is the case - for example, if you're just providing a progress report to the UI, you don't want to stop working just because the UI thread hasn't caught up yet.

On the other hand, if you need to fetch something from the UI thread (which is pretty rare, admittedly) then you might want to use Invoke instead. I'd say you should use BeginInvoke unless you've got a specific reason to use Invoke. But either way, you should understand the difference :)

Jon Skeet
+3  A: 

A very obvious use case for Invoke() is when you need to invoke a method whose return value you need. Only Invoke() can provide this for you, it returns Object, the method return value.

A weaker one is where your worker thread is producing results at a rate far faster than the UI thread can keep up with. Using Invoke() will throttle the worker and the invoke list cannot grow without bound. This however is merely a band-aid for a bigger problem, it doesn't make sense to update the UI any faster than a human can perceive. Once every 40 milliseconds looks smooth to the human eye. You still want to use Invoke() if it takes the UI thread still too much time to process the result collection. Classic signs of having a problem like this is the UI thread freezing, not getting around to painting and responding to mouse and keyboard events because it is completely overwhelmed by invoke requests. And the UI thread staying unresponsive for a while after the worker completed running, busy working off the backlog.

Another case is locking requirements for the object(s) you pass to BeginInvoke(). No locking is required when you use Invoke(), the UI thread and the worker thread cannot access the object at the same time. Not the case for BeginInvoke, it keeps motoring and if the thread keeps using the same object then you have to protect the object with a lock in both the UI thread and the worker. If that locking prevents the worker from making any progress then you might as well use Invoke(). This is all pretty uncommon, it takes a great deal of time for the main thread to start executing the delegate. And it is always a good idea to create a new instance of the object after you invoked so that there's no need for locking.

Hans Passant