当前位置: 首页 > 编程语言 > C#

在C#中模拟撕掉一个doubleshare

时间:2023-04-10 16:20:20 C#

在C#中模拟撕掉一个double我在32位机器上运行,我能够确认使用long值可以快速查看以下代码片段。staticvoidTestTearingLong(){System.Threading.ThreadA=newSystem.Threading.Thread(ThreadA);A.开始();System.Threading.ThreadB=newSystem.Threading.Thread(ThreadB);B.开始();}静态ulongs_x;静态无效ThreadA(){inti=0;while(true){s_x=(i&1)==0?0x0L:0xaaaabbbbbccccddddL;我++;}}staticvoidThreadB(){while(true){ulongx=s_x;调试断言(x==0x0L||x==0xaaaabbbbccccddddL);但是当我尝试类似的双打时,我不会撕裂。有谁知道为什么?据我所知,只有浮点赋值是原语。分配给double应该有撕裂的风险。静态双s_x;staticvoidTestTearingDouble(){System.Threading.ThreadA=newSystem.Threading.Thread(ThreadA);A.开始();System.Threading.ThreadB=newSystem.Threading.Thread(ThreadB);B.开始();}staticvoidThreadA(){longi=0;while(true){s_x=((i&1)==0)?0.0:双倍最大价值;我++;如果(i%10000000==0){Console.Out.WriteLine("i="+i);}}}staticvoidThreadB(){while(true){doublex=s_x;System.Diagnostics.Debug.Assert(x==0.0||x==double.MaxValue);}}静态双s_x;使用双精度执行效果要困难得多。CPU使用专用指令来加载和存储双FLD和FSTP。由于没有一条指令可以在32位模式下加载/存储64位整数,因此很容易。要观察它,您需要使变量的地址未对齐,以便它跨越cpu缓存行边界。使用声明永远不会发生这种情况,JIT编译器确保双精度正确对齐,存储在8的倍数的地址中。您可以将它存储在类的一个字段中,GC分配器仅对齐到432位模式。但那是废话。最好的方法是使用指针故意错位双精度数。将unsafe放在Program类前面,如下所示:staticdouble*s_x;staticvoidMain(string[]args){varmem=Marshal.AllocCoTaskMem(100);s_x=(double*)((long)(mem)+28);TestTearingDouble();线程A:*s_x=((i&1)==0)?0.0:双倍最大价值;线程B:双x=*s_x;这仍然不能保证良好的错位(呵呵),因为无法控制AllocCoTaskMem()将相对于cpu缓存行的开头对齐分配的确切位置。这取决于您的cpu内核中的缓存关联性(我的是Corei5)。你必须修补偏移量,我通过实验得到了值28。该值应能被4整除,但不能被8整除,以真正模拟GC堆行为。继续向该值添加8,直到获得跨越缓存行并触发断言的双精度值。为了减少手动工作,您必须编写一个程序来将双精度值存储在类的一个字段中,并让垃圾收集器在内存中移动它以使其错位。很难想出一个示例程序来确保发生这种情况。还要注意您的程序如何演示称为错误共享的问题。注释掉线程B的Start()方法调用并注意线程A的运行速度。您会看到cpu使缓存行在cpu内核之间保持一致的成本。由于线程访问同一个变量,这里是共享的。当线程访问存储在同一缓存行中的不同变量时,会发生真假共享。这就是对齐很重要的原因,如果它的一部分在一个缓存行中而另一部分在另一个缓存行中,您只能观察到双重撕裂。听起来很奇怪,这取决于您的CPU。虽然不能保证双打不会撕裂,但它们在许多当前处理器上不会撕裂。如果你想在这种情况下rip,试试AMDSempron。编辑:了解几年前的困难。做了一些挖掘,我发现了一些关于x86架构上的浮点运算的有趣阅读:根据维基百科,x86浮点单元将浮点值存储在80位寄存器中:[…]随后的x86处理器然后将x87功能集成到-chip最重要的是,使x87指令成为x86指令集事实上不可或缺的一部分。每个x87寄存器(称为ST(0)到ST(7))都是80位宽,并以IEEE浮点标准双精度扩展格式存储数字。另一个SO问题也相关:一些浮点精度和数值限制问题可以解释为什么尽管双精度数是64位,但它们是原语。对于它的价值,可以在此处找到该主题和代码示例。http://msdn.microsoft.com/zh-cn/magazine/cc817398.aspx以上就是C#学习教程:模拟撕掉C#中的双股一全内容,如果对大家有用需要了解一下more关于C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: