以下对象线程安全吗
本文关键字:安全 线程 对象 | 更新日期: 2023-09-27 18:20:31
以下对象线程安全吗?我将创建一个实例,并使用两个或多个线程来使用它,这是一个很好的方法吗?
public class ASyncBuffer<T>
{
readonly object _locker = new object();
private T _value;
private bool _dirty;
public T GetValue()
{
lock (_locker)
{
_dirty = false;
return _value;
}
}
public void SetValue(T value)
{
lock (_locker)
{
_dirty = true;
_value = value;
}
}
public bool Dirty
{
get
{
lock (_locker)
{
return _dirty;
}
}
}
}
对象本身是线程安全的,但也要考虑它的使用。例如,如果您的用法如下:
if ( buffer.Dirty ) {
var obj = buffer.GetValue();
}
这种用法不是线程安全的,因为Dirty
的值可能在您检查它和实际获得值之间发生变化。
为了避免这个问题(并尽量减少锁定的使用),您应该这样使用它:
if ( buffer.Dirty ) {
lock(buffer) {
if ( buffer.Dirty ) {
var obj = buffer.GetValue();
}
}
}
简而言之:真的没有
一旦你放弃了对价值的所有权,那么你就绝对不能保证会发生什么。当您依赖_value
在if语句中具有某个值(并非双关语)时,这一点变得尤为明显。当这种情况发生时,您所能保证的就是_value
在读取时不会处于某些部分写入状态。
脏旗也是如此。。。坦率地说,脏旗更明显。
考虑这种情况:
Thread 1 calls ASyncBuffer.SetValue(someValue) // sets the dirty flag to true
Thread 1 checks ASyncBuffer.Dirty // should be true
Thread 2 calls ASyncBuffer.GetValue() // sets the flag to false
Thread 1 calls ASyncBuffer.GetValue() // you expect the dirty flag to be true, but it's not
从这个意义上说,它不是线程安全的。
是,但只有在访问属性本身时,一旦使用/分配了属性,就由被操作的对象来处理其内部状态,该状态是以线程安全的方式操作的。
是的,但它的用途可能不是。
我假设您想要检索该值,当且仅当它是"脏"的(因为每次检索时都会清除它,所以我看不到相反的值)。因此,你会这样做:
if(buff.Dirty)
{
T val = buff.GetValue();
//operations on val.
}
但是,如果另一个线程同时调用GetValue()
,那么Dirty
现在为false。
因此,它的使用只对一个读取器线程是安全的(在这种情况下,多个编写器线程是可以的,因为它们只会在相反的方向上更改Dirty
)。
如果你可以有多个阅读器,那么可以考虑添加以下内容:
public bool GetIfDirty(out T value)
{
lock (_locker)
{
if(!_dirty)
{
value = default(T);
return false;
}
_dirty = false;
value = _value;
return true;
}
}
然后,如果需要,您可以在同一个线程安全操作中测试Dirty
并获得值。
AFAIK,这不是一个线程安全的程序。getter和setter将具有不同的锁。有关更多信息,请参阅线程