以下对象线程安全吗

本文关键字:安全 线程 对象 | 更新日期: 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将具有不同的锁。有关更多信息,请参阅线程