以下对象线程是否安全? 我将创建一个实例并使用两个或多个线程来使用它,这是一个很好的方法吗?
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;
}
}
}
}
答案 0 :(得分:7)
对象本身是线程安全的,但请确保您也考虑使用它。例如,如果您的用法如下所示:
if ( buffer.Dirty ) {
var obj = buffer.GetValue();
}
该用法不是线程安全的,因为Dirty
的值在您检查它和实际获得值之间可能会发生变化。
为了避免这个问题(并尽量少使用锁定),您可能希望像以下一样使用它:
if ( buffer.Dirty ) {
lock(buffer) {
if ( buffer.Dirty ) {
var obj = buffer.GetValue();
}
}
}
答案 1 :(得分:1)
简而言之:没有真的。
一旦放弃了价值的所有权,那么你就无法保证将会发生什么。当你依赖_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
从这个意义上讲,它不是线程安全的。
答案 2 :(得分:0)
YES但是只有在访问属性本身时,一旦使用/分配了属性,则由被操纵的对象来处理以线程安全方式操作的内部状态。
答案 3 :(得分:0)
是的,但它的使用可能不是。
我假设您想要检索该值,并且仅当它是“脏”时(因为每次检索都会清除它,所以我看不到相反的值)。你会这样做:
if(buff.Dirty)
{
T val = buff.GetValue();
//operations on val.
}
但是,如果另一个帖子同时调用GetValue()
,则Dirty
现在为假。
因此,它的使用对于一个读者线程是安全的(在这种情况下,多个写入者线程很好,因为它们只会在相反的方向上改变Dirty
。)
如果您有多个读者,请考虑添加以下内容:
public bool GetIfDirty(out T value)
{
lock (_locker)
{
if(!_dirty)
{
value = default(T);
return false;
}
_dirty = false;
value = _value;
return true;
}
}
然后你可以在相同的线程安全操作中测试Dirty
并获得所需的值。
答案 4 :(得分:-3)
AFAIK,这不是一个线程安全的程序。你的getter和setter会有不同的锁。有关详细信息,请参阅thread