在我的多线程应用程序中,我使用的是一些可以在同一时间被许多实例更改的变量。这很奇怪,但它没有任何问题,但工作正常。但我当然需要让它具有线程安全性。我刚开始使用锁,所以我会建议你的建议:
当客户端连接时,会创建类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
}
}
会没事吗?
答案 0 :(得分:16)
你需要在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;
}
}
}
答案 1 :(得分:6)
锁定对访问者内部属性的访问可能会导致虚假结果。例如,请查看以下代码:
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,任何对象都可以)
答案 2 :(得分:2)
当你需要的只是设置一个属性时,这是非常罕见的。更常见的是selectedClient.A = 5
将成为更大的逻辑操作的一部分,其涉及若干任务/评估/等。在整个操作期间,您宁愿优先selectedClient
处于一致状态而不是引入死锁/竞争条件。因此,在SyncRoot
类中公开Client
属性并从调用代码中锁定该属性会好得多:
Client selectedClient = GetClient(...);
lock(selectedClient.SyncRoot)
{
selectedClient.A = 5;
selectedClient.B = selectedClient.A * 54;
}