我原以为是单线程单元机制,但本文档指出这仅适用于 COM 对象。
有谁知道Windows窗体使用什么机制来强制其线程相关性?
TL;DR:它将当前调用的线程 ID 与用于创建控件的窗口句柄的线程 ID 进行比较。如果它们不同,则会引发异常。
如果您查看Windows.Forms.Control的引用源,您会发现一个名为CheckForIllegalCrossThreadCalls
的属性:
public static bool CheckForIllegalCrossThreadCalls {
get { return checkForIllegalCrossThreadCalls; }
set { checkForIllegalCrossThreadCalls = value; }
}
每当检索句柄时都会使用此方法:
public IntPtr Handle {
get {
if (checkForIllegalCrossThreadCalls &&
!inCrossThreadSafeCall &&
InvokeRequired) {
throw new InvalidOperationException(SR.GetString(SR.IllegalCrossThreadCall,
Name));
}
if (!IsHandleCreated)
{
CreateHandle();
}
return HandleInternal;
}
}
由于在需要控件句柄的任何位置都访问Handle
因此这是代码检查跨线程调用的逻辑位置。
它利用 InvokeRequired
属性来查看何时会发生跨线程调用。
InvokedRequired
本身就有些牵扯到:
public bool InvokeRequired {
get {
using (new MultithreadSafeCallScope())
{
HandleRef hwnd;
if (IsHandleCreated) {
hwnd = new HandleRef(this, Handle);
}
else {
Control marshalingControl = FindMarshalingControl();
if (!marshalingControl.IsHandleCreated) {
return false;
}
hwnd = new HandleRef(marshalingControl, marshalingControl.Handle);
}
int pid;
int hwndThread = SafeNativeMethods.GetWindowThreadProcessId(hwnd, out pid);
int currentThread = SafeNativeMethods.GetCurrentThreadId();
return(hwndThread != currentThread);
}
}
}