这是实现线程安全的读/写Guid属性的正确方法吗?

本文关键字:属性 方法 Guid 实现 线程 安全 | 更新日期: 2023-09-27 18:18:58

我正在实现一个将从多个线程并发使用的类。大多数属性获取和设置可以由Interlocked类正确处理的基本类型。这个类包含一个Guid属性。这不是以线程安全的方式直接实现的。这就是你实现属性的方式吗?提前谢谢。

private Byte[] _activityId;
public Guid ActivityId 
    {
        get { return new Guid(this._activityId); }
        set
        {
            Byte[] bytes = value.ToByteArray();
            Interlocked.Exchange(ref this._activityId, bytes);
        }
    }

UPDATE:所以到目前为止,唯一提出的解决方案不包括使用任何"线程"类或结构。所以我要提出我在评论中已经提出的问题:

我的理解是引用/原始值类型的赋值是原子的,但是Interlocked将保证更改传播到所有线程。如果我们可以简单地赋值,为什么Interlocked会公开api来交换引用类型和原始值呢?

这是实现线程安全的读/写Guid属性的正确方法吗?

您可以通过创建自己的box类来获得更便宜的原子赋值:

class Box<T> where T : struct {
    public readonly T Value;
    public Box(T value) { Value = value; }
}

通过存储对(不可变的)Box实例的引用而不是直接存储值,对该字段的所有操作都将是原子的。

private Box<Guid> _activityId;
public Guid ActivityId {
    get { return this._activityId.Value; }
    set { this._activityId = new Box<Guid>(value); }
}

这样,非原子结构体复制操作发生在new Box<Guid>(value).Value访问中。因为不涉及现场,所以不会造成麻烦。

这应该比使用字节数组快得多,比使用强制类型转换的本机装箱快一点。(免责声明:我没有测量过)

我认为您可以使用Interlocked.Exchange的其他过载:

private volatile object _activityId; // Yes, object :)
public Guid ActivityId {
    get { return (Guid)_activityId; }
    set { _activityId = value; }
}
这是因为Guid现在被装箱,并且引用类型的赋值是原子的。