views:

202

answers:

3

is there any documentation on exactly how expensive it is:

if (x.IsInvokeRequired) { beginInvoke . . . . }

  • If you have a case where 90% pct of the time is on a background thread (and thus required) is it worth it?
  • If you have a case where 90% pct of the time is on a UI thread (and thus not required) is it worth it?

Any metrics around this would be great.

+2  A: 

InvokeRequired's cost depends on which class is implementing ISynchronizeInvoke, and the specific usage case. The "cost" will very depending on the implementation you are using. However, in general, it's typically a fairly low overhead call. (In many cases, it can be as simple as a check to see if the current thread is the same as the original thread.)

That being said, if you need it, it's worth the cost, ALWAYS. Even if it's only 1% of the time that it will be required, it should be included. Otherwise, you are asking for a crash, lock, or some other very undesirable behavior. Most cases where you could be using this are cases where you should always include this cost.

The most common use case is synchronizing delegates onto the UI thread. In this case, you must use it, or very bad things happen... Also, in this case, the cost is very low compared to the waiting on the message pump for UI interactions, so it's really not worth worrying about.

If you are using it with a custom implementation of ISynchronizeInvoke, and it's happening in a tight loop, AND you've profiled and found that it's causing problems for you, then it may be worth worrying about. In this case, though, I would recommend trying to rework the algorithm itself to avoid the need for synchronizing as much as possible, but still use InvokeRequired as needed.

Reed Copsey
+3  A: 

Real Answer:

Use a profiler

Fuzzy Answer:

I think you need to consider the relative costs of both functions vs. the absolute cost of InvokeRequired.

InvokeRequired for Control essentially compares the current ThreadId with the expected ThreadId. If you look in reflector the code is slightly more complex but in effect that's what it's doing. This is fairly cheap as it's just a few function calls and a comparison.

BeginInvoke involves taking several locks, adding delegates to an invoke queue and potentially a Marshal between threads. This code is much more expensive relative to the actual InvokeRequired call (likely an order of magnitude or 2). You would need a great deal more calls where InvokeRequired returns true before you would see any gain by just going straight to BeignInvoke.

JaredPar
+2  A: 

No metrics, but a quick trip into Reflector tells us that the call is most likely not very expensive at all:

[SRDescription("ControlInvokeRequiredDescr"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public bool InvokeRequired
        {
            get
            {
                using (new MultithreadSafeCallScope())
                {
                    HandleRef ref2;
                    int num;
                    if (this.IsHandleCreated)
                    {
                        ref2 = new HandleRef(this, this.Handle);
                    }
                    else
                    {
                        Control wrapper = this.FindMarshalingControl();
                        if (!wrapper.IsHandleCreated)
                        {
                            return false;
                        }
                        ref2 = new HandleRef(wrapper, wrapper.Handle);
                    }
                    int windowThreadProcessId = SafeNativeMethods.GetWindowThreadProcessId(ref2, out num);
                    int currentThreadId = SafeNativeMethods.GetCurrentThreadId();
                    return (windowThreadProcessId != currentThreadId);
                }
            }
        }

It's likely best to make the check regardless of the usage, as any performance gain from this sort of micro-optimization would be more than offset by the risk of an issue popping up.

Craig Vermeer