以下对象线程是否安全?

时间:2012-01-17 21:38:21

标签: c# .net multithreading

以下对象线程是否安全? 我将创建一个实例并使用两个或多个线程来使用它,这是一个很好的方法吗?

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;
            }
        }
    }
}

5 个答案:

答案 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