What about Form.Invoke when already in the right thread?
I've got a code block that has to be executed in the same thread as the window. So I'd like call Form.Invoke for this block. But the method, containing the code block, can be calle开发者_运维技巧d from different threads and one of them is the window thread.
So my question is: Is it ok to just use Form.Invoke although the method might be called already in the right thread? Or does this generate an overhead or even be a possible source of error?
Yes it is fine to call Invoke
from the thread that owns the handle.
The overwhelming majority of code samples suggest that you should test InvokeRequired
before deciding whether or not to call Invoke
.
if (control.InvokeRequired)
{
control.Invoke(action);
}
else
{
action();
}
However, this leads to rather cluttered code and if you must support calls from non-GUI threads then I recommend that you simply call Invoke
directly in all cases. There is a small overhead versus calling InvokeRequired
and then the delgate directly - see Hans Passant's comments to the question. However, so long as the delegate is performing significant work, or this code is not in a hot spot, the overhead should matter less than the code clarity.
What's more InvokeRequired
can give misleading results in the control's handle has not yet been allocated. The documentation states:
If the control's handle does not yet exist, InvokeRequired searches up the control's parent chain until it finds a control or form that does have a window handle. If no appropriate handle can be found, the InvokeRequired method returns false.
This means that InvokeRequired can return false if Invoke is not required (the call occurs on the same thread), or if the control was created on a different thread but the control's handle has not yet been created.
In the case where the control's handle has not yet been created, you should not simply call properties, methods, or events on the control. This might cause the control's handle to be created on the background thread, isolating the control on a thread without a message pump and making the application unstable.
You can protect against this case by also checking the value of IsHandleCreated when InvokeRequired returns false on a background thread. If the control handle has not yet been created, you must wait until it has been created before calling Invoke or BeginInvoke. Typically, this happens only if a background thread is created in the constructor of the primary form for the application (as in Application.Run(new MainForm()), before the form has been shown or Application.Run has been called.
So I would take the advice from the final quoted paragraph above and replace the risky InvokeRequired
code above with:
control.Invoke(action);
You can check if you need to call Invoke
.
if (myForm.InvokeRequired)
{
// do invoke staff
} else
{
// just execute your code without invoking
}
精彩评论