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