C# 锁定属性,好方法?

C# 锁定属性,好方法?,c#,winforms,multithreading,C#,Winforms,Multithreading,在我的多线程应用程序中,我使用了一些可以由多个实例同时更改的变量。这很奇怪,但它工作得很好,没有任何问题。但我当然需要使它线程安全。我刚开始使用锁,所以我想听听你的建议: 当客户端连接时,将创建类客户端,其中每个客户端都有自己的“A”变量 有时,客户机调用这样的方法: Client selectedClient SelectOtherClientClassByID(sentID); selectedClient.A=5; 到目前为止,即使有5个类同时运行(threadpool),也没有问题,

在我的多线程应用程序中,我使用了一些可以由多个实例同时更改的变量。这很奇怪,但它工作得很好,没有任何问题。但我当然需要使它线程安全。我刚开始使用锁,所以我想听听你的建议:

当客户端连接时,将创建类客户端,其中每个客户端都有自己的“A”变量

有时,客户机调用这样的方法:

Client selectedClient SelectOtherClientClassByID(sentID);

selectedClient.A=5;
到目前为止,即使有5个类同时运行(threadpool),也没有问题,但我在想,如何向属性添加锁

比如:


可以吗?

在get和set中都需要使用锁。此锁必须是同一对象。例如:

private object mylock = new object();

public int A {

  get {
    int result;
    lock(mylock) {
    result = mA; 
    }
    return result;
  } 

  set { 
     lock(mylock) { 
        mA = value; 
     }
  }
}

当您只需要设置一个属性时,这是非常罕见的。通常情况下,
selectedClient.A=5
将是更大的逻辑操作的一部分,该操作涉及多个赋值/求值等。在整个操作过程中,您更希望
selectedClient
处于一致状态,而不是引入死锁/竞争条件。因此,最好在
客户机
类中公开
SyncRoot
属性,并从调用代码锁定该属性:

Client selectedClient = GetClient(...);

lock(selectedClient.SyncRoot)
{
    selectedClient.A = 5;
    selectedClient.B = selectedClient.A * 54;
}

锁定对访问者内部属性的访问可能会导致虚假结果。对于该示例,请查看以下代码:

class C {
    private object mylock = new object();

    public int A {

      get {
        int result;
        lock(mylock) {
        result = mA; 
        }
        return result;
      } 

      set { 
         lock(mylock) { 
            mA = value; 
         }
      }
    }
}
C obj = new C;
C.A++;
(是的,我从第一个答案中复制了它) 这里有比赛条件!操作“C.A++”实际上需要对A进行两次单独的访问,一次获取值,另一次设置更新后的值。没有任何东西可以确保这两个访问在没有上下文切换的情况下一起执行。比赛条件的经典场景


所以,当心!将锁放在访问器中不是一个好主意,锁应该被显式地获取,就像前面的答案所建议的那样(虽然它不必与SyncRoots一起使用,任何对象都可以)

谢谢你…顺便说一句,因为它可以在其他类的读取过程中更改?锁定它不是一个好主意,因为它可以从类型外部访问。在设置时它可能会更改。锁起到了屏障的作用,在锁所有者释放锁之前阻止任何其他动作。@Brian,我同意。对我的代码进行了更改。只是演示而已。对不起,我参加了会议,\n请注意,您的代码在更改之前是什么样子的,我的意思是Brian提到的问题是什么?我喜欢尽可能多地学习:)除了一个列表和那些int之外,我没有其他变量共享。主要是,我对SyncRoot一无所知:)不建议使用SyncRoot:请参阅"NT"引用博客文章中的话:“请放心,我们在构建这些集合的通用版本时不会犯同样的错误。”6年后,我们就到了,在MSDN中没有任何令人沮丧的注释的情况下使用List.SyncRoot:MSDN几乎不是正确编程的最佳资源!SyncRoot,是一个公共锁和一个即将发生的灾难(根据Jeffrey Richter通过C#的CLR)吗?你的意思是手动将锁对象添加到代码中的所有调用中?我想到目前为止,我的代码中至少有20个阅读和15个写作。为此,您需要扩展锁以覆盖整个关键区域。NT:我可能不太了解你。我有大约15个方法,在不同的实例上使用该变量进行不同的操作。我不知道你扩充锁的意思。因此,如果我正确读取所有属性,那么属性锁就不好above@Petr当前位置我将之前的评论转给了伊利尔。至于您的评论,您需要确定它们是否有一个共同的同步对象。在这种情况下,你应该使用一把锁。如果您对所有这些都不熟悉,请查看以下有趣的链接:
class C {
    private object mylock = new object();

    public int A {

      get {
        int result;
        lock(mylock) {
        result = mA; 
        }
        return result;
      } 

      set { 
         lock(mylock) { 
            mA = value; 
         }
      }
    }
}
C obj = new C;
C.A++;