锁定属性,好方法?

在我的multithreading应用程序中,我使用的是一些可以在同一时间被许多实例更改的变量。 这很奇怪,但它没有任何问题,但工作正常。但我当然需要让它具有线程安全性。 我刚开始使用锁,所以我会建议你:

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

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

Client selectedClient SelectOtherClientClassByID(sentID); selectedClient.A=5; 

直到现在还没有问题,即使5个类同时进行(线程池),但我在考虑如何为A属性添加锁?

喜欢:

 A { get { return mA; } set { // use lock here for settting A to some value } } 

会没事吗?

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

 private object mylock = new object(); public int A { get { int result; lock(mylock) { result = mA; } return result; } set { lock(mylock) { mA = value; } } } 

锁定对访问者内部属性的访问可能会导致伪造结果。 有关示例,请查看以下代码:

 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一起使用,任何对象都可以)

当你需要的只是设置一个属性时,这是非常罕见的。 更常见的selectedClient.A = 5将是更大的逻辑操作的一部分,其涉及若干任务/评估/等。 在整个操作期间,您宁愿选择selectedClient处于一致状态而不是引入死锁/竞争条件。 因此,在Client类中公开SyncRoot属性并从调用代码锁定它会更好:

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