WinForms 如何强制实施线程相关性



我原以为是单线程单元机制,但本文档指出这仅适用于 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);
            }
        }
    }

最新更新