我正在实现一个将从多个线程同时使用的类。大多数属性获取并设置原始类型,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);
}
}
更新:因此到目前为止唯一提出的解决方案不包括使用任何“线程”类或结构。所以我将提出我已在评论中提出的问题:
我的理解是引用/原始值类型赋值是原子的,但Interlocked将保证更改传播到所有线程。如果我们只是简单地分配值,为什么Interlocked会公开API以交换引用类型和原始值?
答案 0 :(得分:4)
您可以通过创建自己的盒子类来获得更便宜的原子分配:
class Box<T> where T : struct {
public readonly T Value;
public Box(T value) { Value = value; }
}
通过存储对(immutable)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
访问中。由于他们不涉及该领域,他们不会造成麻烦。
这应该比使用字节数组快得多,并且比使用强制转换的本机装箱快一点。 (免责声明:我没有测量过)
答案 1 :(得分:2)
我认为您可以使用Interlocked.Exchange
的其他重载:
private volatile object _activityId; // Yes, object :)
public Guid ActivityId {
get { return (Guid)_activityId; }
set { _activityId = value; }
}
这是有效的,因为Guid
现在已装箱,并且引用类型的分配是原子的。