public ArrayList InputBuffer
{
get { lock (this.in_buffer) { return this.in_buffer; } }
}
在调用InputBuffer.Clear?
时是否锁定了this.in_buffer或者属性是否只是在获取对它的引用时锁定in_buffer对象;锁定退出,然后该引用用于清除?
答案 0 :(得分:5)
不,该属性在获取引用时锁定引用。毫无意义,说实话......这种情况比较常见:
private readonly object mutex = new object();
private Foo foo = ...;
public Foo Foo
{
get
{
lock(mutex)
{
return foo;
}
}
}
该锁只会 覆盖属性访问本身,并且不会对使用Foo
执行的操作提供任何保护。但是,不与完全没有锁相同,因为只要变量只是写而持有相同的锁,它确保您在任何时候阅读Foo
属性,您正在访问该属性的最新值...没有锁定,没有内存障碍,您可能会得到“陈旧”的结果。
这很弱,但值得了解。
就个人而言,我尝试使极少数类型的线程安全,并且那些往往有更合适的操作...但是如果你想编写做的修改和读取多个线程的属性的代码,这是这样做的一种方式。使用volatile
也可以提供帮助,但它的语义非常微妙。
答案 1 :(得分:2)
对象被锁定在锁定调用的大括号内,然后它被解锁。
在这种情况下,锁定调用中唯一的代码是return this.in_buffer;
。
因此,在这种情况下,在调用InputBuffer.Clear期间,in_buffer未被锁定。
使用扩展方法解决您的问题的方法如下:
private readonly object _bufLock;
class EMClass{
public static void LockedClear(this ArrayList a){
lock(_bufLock){
a.Clear();
}
}
}
现在你做的时候:
a.LockedClear();
Clear通话将在锁定中完成。
您必须确保仅在_bufLocks中访问缓冲区。
答案 2 :(得分:1)
除了其他人对锁的范围所说的内容之外,请记住你没有锁定对象,你只是基于对象实例锁定命名。
通常的做法是使用单独的锁互斥锁,如Jon Skeet所示。
如果在清除集合时必须保证同步执行,请公开一个清除集合的方法,让客户端调用它,并且不公开底层实现细节。 (无论如何,这都是好的做法 - 查看封装。)
答案 3 :(得分:1)
如前所述,这种锁定形式没有帮助。
public ArrayList InputBuffer
{
get { lock (this.in_buffer) { return this.in_buffer; } }
}
因为它只将引用锁定到 ArrayList,而不是ArrayList本身。 lock(x) { }
的设计可能有点误导。它不会以任何方式改变(锁定)x
的状态。
您似乎需要的是:
private ArrayList _inBuffer;
private object _bufferLock;
public object GetItem(int x)
{
lock (_bufferLock) { return _inBuffer[x]; }
}
public void SetItem(int x, object value)
{
lock (_bufferLock) { _inBuffer[x] = value; }
}
围绕_inBuffer.Clear()
等的类似方法