加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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字节的结构所呈现的任何其他抽象必然是“泄漏的”,尤其是关于多线程行为,一个结构体更好地呈现它本身就是它,而不是假装它不是它的东西.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读