我知道,只要涉及的数据可以适合双字(32位),原子性就应该得到保证.无论操作系统是32位还是64位.
现在,考虑以下“长”代理人……
注意:我省略了几种方法,因为我不需要它们.在这种情况下,我只需要基本转换为/从真正的长.
public struct SafeLong : IConvertible { public SafeLong(long value) { unchecked { var arg = (ulong)value; this._data = new byte[] { (byte)arg,(byte)(arg >> 8),(byte)(arg >> 16),(byte)(arg >> 24),(byte)(arg >> 32),(byte)(arg >> 40),(byte)(arg >> 48),(byte)(arg >> 56),}; } } private byte[] _data; private long Value { get { unchecked { var lo = this._data[0] | this._data[1] << 8 | this._data[2] << 16 | this._data[3] << 24; var hi = this._data[4] | this._data[5] << 8 | this._data[6] << 16 | this._data[7] << 24; return (long)((uint)lo | (ulong)(uint)hi << 32); } } } public static implicit operator long(SafeLong value) { return value.Value; // implicit conversion } public static explicit operator SafeLong(long value) { return new SafeLong(value); // explicit conversion } #region IConvertible implementation public TypeCode GetTypeCode() { return Type.GetTypeCode(typeof(SafeLong)); } public object ToType(Type conversionType,IFormatProvider provider) { return Convert.ChangeType(this.Value,conversionType); } public long ToInt64(IFormatProvider provider) { return this.Value; } // ... OMISSIS (not implemented) ... #endregion }
好吧,它看起来像我期望的那样完美.
这是一个小测试:
class Program { static void Main(string[] args) { var sla = (SafeLong)12345678987654321L; var la = (long)sla; Console.WriteLine(la); var slb = (SafeLong)(-998877665544332211L); var lb = (long)slb; Console.WriteLine(lb); Console.WriteLine(Marshal.SizeOf(typeof(SafeLong))); Console.WriteLine(Marshal.SizeOf(sla)); Console.WriteLine(Marshal.SizeOf(slb)); long lc = new SafeLong(556677); var slc = slb; Console.WriteLine(slc); slc = (SafeLong)lc; Console.WriteLine(slc); Console.WriteLine(slb); Console.Write("Press any key..."); Console.ReadKey(); } }
SizeOf函数总是产生4个字节作为我的代理的大小.这个值是否保证了SafeLong-to-SafeLong副本的原子性,或者4个字节应该被解释为“真正的物理双字”?
无论长< - >的非原子性如何. SafeLong:它将被包含在安全的上下文中.
非常感谢提前.
解决方法
public struct SafeThing<T> where T : struct { private object BoxedThing; public SafeThing(T value) { BoxedThing = value; } public T Value { get { return BoxedThing == null ? default(T) : (T)BoxedThing; } } public static implicit operator T(SafeThing<T> value) { return value.Value; } public static implicit operator SafeThing<T>(T value) { return new SafeThing(value); } }
而且你已经完成了.你为什么要用阵列搞乱这一切?
另外,我注意到在您的实现中,您已经向后转换了显式/隐式转换.如果转换无损且不抛出,则只应隐式转换.您从SafeLong到long的隐式转换可以抛出,因此它不应该是隐式的.你从long到SafeLong的显式转换不能抛出并且是无损的,所以如果你想要的话它可能是隐含的.正如你所看到的,我已经通过使两个方向无损且无投掷来解决我的实现中的问题,因此它们都是隐含的.
请注意,此结构本质上是一个围绕盒装值的强类型包装器;如果在CLR的第一个版本中可以使用泛型类型,毫无疑问,盒装值类型将使用某种类型的类型实现,就像可空值类型类似地通过特殊泛型类型实现一样.
The SizeOf function yields always 4 bytes as the size of my surrogate. Does this value guarantees the atomicity of a copy SafeLong-to-SafeLong?
嗯,是的,不.
首先,“SizeOf”方法不会在内存中给出结构的大小;它在跨越托管/非托管边界持久化时给出结构的大小.这不一定与托管内存中结构的大小相同;它通常是相同的,但不保证是相同的.如果您想知道托管内存中结构的大小,则需要打开“不安全”模式并使用“sizeof”运算符.
实际上,大小为4的结构的副本总是原子的,只要它被复制到四字节边界上对齐的位置即可.语言规范并不保证任何四字节结构将以原子方式复制,但实际上在我们的实现中也是如此.
在您的特定情况下,这四个字节是对数组的引用;语言规范确保始终以原子方式复制引用.