WinForms如何强制执行线程关联?

时间:2016-02-01 20:41:26

标签: c# multithreading winforms

我原以为是Single-Threaded Apartment机制,但是this documentation表示只适用于COM对象。

有谁知道Windows Forms用于强制执行其线程关联的机制

1 个答案:

答案 0 :(得分:4)

TL; DR:它将当前调用的线程id与用于创建控件的Window句柄的线程id进行比较。如果它们不同,则抛出异常。

如果查看the reference source for 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);
            }
        }
    }