c# – 类成员vs结构成员上使用volatile写入的奇怪行为
发布时间:2020-12-15 21:52:25 所属栏目:百科 来源:网络整理
导读:我正在开发一个需要具有volatile语义的long类型的组件. 由于.NET中没有volatile,我创建了一个简单的包装器类型,它使用Volatile类处理读/写访问. 我不确定是否应该使用类或结构,所以我决定对它们进行测试,然后我遇到了一个非常奇怪的行为. 这是测试代码: int
我正在开发一个需要具有volatile语义的long类型的组件.
由于.NET中没有volatile,我创建了一个简单的包装器类型,它使用Volatile类处理读/写访问. 我不确定是否应该使用类或结构,所以我决定对它们进行测试,然后我遇到了一个非常奇怪的行为. 这是测试代码: internal class Program { private class VolatileLongClass { private long value; public long Value { get { return Volatile.Read(ref value); } set { Volatile.Write(ref this.value,value); } } } private struct VolatileLongStruct { private long value; public long Value { get { return Volatile.Read(ref value); } set { Volatile.Write(ref this.value,value); } } } private static void Main() { const int iterations = 10; var totalTime = 0L; for (var i = 0; i < iterations; i++) { var watch = Stopwatch.StartNew(); var volatileLong = new VolatileLongClass(); //<-- change to VolatileLongStruct for (var j = 0L; j < 10 * 1000 * 1000; j++) volatileLong.Value = j; var msElapsed = watch.ElapsedMilliseconds; Console.Out.WriteLine("Ms Elapsed = {0}",msElapsed); totalTime += msElapsed; } Console.Out.WriteLine("Avg = {0:N2}",(double) totalTime / iterations); } } 我得到的VolatileLongStruct的输出: Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Avg = 109.00 结构的上述输出是一致的.但是,VolatileLongClass的输出是: Ms Elapsed = 17558 <-- *** Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 17541 <-- *** Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 105 Avg = 3,593.90 正如您所看到的,某些迭代存在很大的时间差异.花费异常时间的精确迭代略有不同,但至少有一次迭代存在一致的问题. 有人可以解释为什么一个易变的写入(有时)在类成员上(有时)长于结构成员吗? 顺便说一句,上面的结果是使用.Net 4.5和Release版本生成的 解决方法
时差很可能是var volatileLong = new VolatileLongClass()的结果;循环内;该语句使编译器 – 一次 – 分配空间来保存VolatileLongClass引用,然后在每次通过循环时创建一个新对象并将引用存储到该位置.相比之下,语句var volatileLong = new VolatileLongStruct();导致编译器 – 一次 – 分配空间来保存VolatileLongStruct实例,然后在每次通过循环时通过将所有数据归零(使用正常而非易失性写入)来改变预先存在的实例.
请注意,如果代码将要求结构字段具有特定的多线程语义,则这些字段通常应该公开,并且结构应该被视为与管道磁带粘在一起的一组变量[例如public struct IntPair {public int V1,V2;} IntPair myPair;应该被视为创建两个单独的变量myPair.V1和myPair.V2].事实上,结构是由管道磁带粘在一起的变量的组合,并且由于大小不是1,2或4字节的结构所呈现的任何其他抽象必然是“泄漏的”,尤其是关于多线程行为,一个结构体更好地呈现它本身就是它,而不是假装它不是它的东西. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |