C# 在C中保护方法不被另一个线程调用的最佳方法#

C# 在C中保护方法不被另一个线程调用的最佳方法#,c#,multithreading,C#,Multithreading,我希望只允许从创建对象的同一线程调用类的所有方法。与Windows窗体控件的方式相同,Windows窗体控件不允许在除UI线程之外的任何其他线程上访问其方法/属性,如果您尝试这样做,它们会引发异常。winforms的控件是如何执行这种行为的?有什么东西我可以用来注释方法(比如一些特殊属性)或者我必须“手工”处理这些情况吗 编辑1: 以下是WinForms控件类的句柄属性getter的代码 public IntPtr Handle { get { if (checkForI

我希望只允许从创建对象的同一线程调用类的所有方法。与Windows窗体控件的方式相同,Windows窗体控件不允许在除UI线程之外的任何其他线程上访问其方法/属性,如果您尝试这样做,它们会引发异常。winforms的控件是如何执行这种行为的?有什么东西我可以用来注释方法(比如一些特殊属性)或者我必须“手工”处理这些情况吗

编辑1: 以下是WinForms控件类的句柄属性getter的代码

public IntPtr Handle {
    get {
        if (checkForIllegalCrossThreadCalls &&
            !inCrossThreadSafeCall &&
            InvokeRequired) {
            throw new InvalidOperationException(SR.GetString(SR.IllegalCrossThreadCall,
                                                             Name));
        }

        if (!IsHandleCreated)
        {
            CreateHandle();
        }

        return HandleInternal;
    }
}
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);
        }
    }
}
这是WinForms控件类所需的invoker代码

public IntPtr Handle {
    get {
        if (checkForIllegalCrossThreadCalls &&
            !inCrossThreadSafeCall &&
            InvokeRequired) {
            throw new InvalidOperationException(SR.GetString(SR.IllegalCrossThreadCall,
                                                             Name));
        }

        if (!IsHandleCreated)
        {
            CreateHandle();
        }

        return HandleInternal;
    }
}
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);
        }
    }
}
查看这段代码,我可以看到问题的一个解决方案是在对象的构造函数中,我们将当前线程id存储在private字段中,然后在每次后续调用中检查当前线程id是否与我们存储的id不同,如果是这样的话,抛出
invalidoOperationException
。您是否发现上述解决方案存在任何问题,或者您是否知道更好的方法

 static class Program
    {
        static void Main()
        {
            MySafeClass c = new MySafeClass();
            Task.Factory.StartNew(() => c.Operation1(), TaskCreationOptions.LongRunning); // This should throw an exception
        }
    }

    class MySafeClass
    {
        private readonly int creationThreadId;

        public MySafeClass()
        {
            creationThreadId = Thread.CurrentThread.ManagedThreadId;
        }

        private void CheckCrossThreadOperation()
        {
            if (this.creationThreadId != Thread.CurrentThread.ManagedThreadId)
            {
                throw new InvalidOperationException("Cross thread operatoin is not allowed");
            }
        }

        public void Operation1()
        {
            CheckCrossThreadOperation();
            // ...
        }

        public void Operation2()
        {
            CheckCrossThreadOperation();
            // ...
        }
    }

向我们展示您到目前为止所做的工作。您可以在methods类中创建一个UI元素,然后检查该元素在方法中的dispatcher访问权限。请查看。为什么需要此限制?如果是因为你制作了一个监听事件的控件,你可能会从成为一个控件中获益,否则我猜你将不得不“手动”实现ISynchronizeInvoke。列表也不是线程安全的,而且你不会看到ms强迫我们跳转使用它。除非你真的要告诉我们你到目前为止做了什么,否则不要妨碍你未来的自我。你可以在methods类中创建一个UI元素,然后在方法中检查它的dispatcher访问。看看。你为什么想要这个限制?如果是因为你制作了一个监听事件的控件,你可能会从成为一个控件中获益,否则我猜你将不得不“手动”实现ISynchronizeInvoke。列表也不是线程安全的,而且你不会看到ms强迫我们跳转使用它。不要妨碍你未来的自我,除非你真的不得不这样做