Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# .NET 3.5SP1 64位内存模型与32位内存模型_C#_.net_64 Bit_32 Bit - Fatal编程技术网

C# .NET 3.5SP1 64位内存模型与32位内存模型

C# .NET 3.5SP1 64位内存模型与32位内存模型,c#,.net,64-bit,32-bit,C#,.net,64 Bit,32 Bit,据我所知,32位机器上的.NET内存模型保证32位字的写入和读取是原子操作,但不保证64位字的写入和读取。我已经编写了一个快速工具,在WindowsXP32位操作系统上演示了这种效果,并且得到了与内存模型描述一致的结果 然而,我使用了同一个工具的可执行文件,并在Windows7Enterprise64位操作系统上运行了它,得到了完全不同的结果。这两台机器的规格相同,只是安装了不同的操作系统。我原以为.NET内存模型将保证在64位操作系统上对32位和64位字的写入和读取都是原子的。我发现结果与这两

据我所知,32位机器上的.NET内存模型保证32位字的写入和读取是原子操作,但不保证64位字的写入和读取。我已经编写了一个快速工具,在WindowsXP32位操作系统上演示了这种效果,并且得到了与内存模型描述一致的结果

然而,我使用了同一个工具的可执行文件,并在Windows7Enterprise64位操作系统上运行了它,得到了完全不同的结果。这两台机器的规格相同,只是安装了不同的操作系统。我原以为.NET内存模型将保证在64位操作系统上对32位和64位字的写入和读取都是原子的。我发现结果与这两个假设完全相反。在这个操作系统上,32位读写并不是原子的

有人能给我解释一下为什么在64位操作系统上会失败吗

工具代码:

using System;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var th = new Thread(new ThreadStart(RunThread));
            var th2 = new Thread(new ThreadStart(RunThread));
            int lastRecordedInt = 0;
            long lastRecordedLong = 0L;
            th.Start();
            th2.Start();
            while (!done)
            {
                int newIntValue = intValue;
                long newLongValue = longValue;
                if (lastRecordedInt > newIntValue) Console.WriteLine("BING(int)! {0} > {1}, {2}", lastRecordedInt, newIntValue, (lastRecordedInt - newIntValue));
                if (lastRecordedLong > newLongValue) Console.WriteLine("BING(long)! {0} > {1}, {2}", lastRecordedLong, newLongValue, (lastRecordedLong - newLongValue));
                lastRecordedInt = newIntValue;
                lastRecordedLong = newLongValue;
            }
            th.Join();
            th2.Join();
            Console.WriteLine("{0} =? {2}, {1} =? {3}", intValue, longValue, Int32.MaxValue / 2, (long)Int32.MaxValue + (Int32.MaxValue / 2));
        }

        private static long longValue = Int32.MaxValue;
        private static int intValue;
        private static bool done = false;

        static void RunThread()
        {
            for (int i = 0; i < Int32.MaxValue / 4; ++i)
            {
                ++longValue;
                ++intValue;
            }
            done = true;
        }
    }
}
请注意BING(int)是如何从不被写入的,它演示了32位读/写在这个32位操作系统上是原子的

Windows 7 Enterprise 64位上的结果:

Windows 7 Enterprise 64-bit
Intel Core2 Duo P8700 @ 2.53GHz
BING(long)! 2208482159 > 2208121217, 360942
BING(int)! 280292777 > 279704627, 588150
BING(int)! 308158865 > 308131694, 27171
BING(long)! 2549116628 > 2548884894, 231734
BING(int)! 534815527 > 534708027, 107500
BING(int)! 545113548 > 544270063, 843485
BING(long)! 2710030799 > 2709941968, 88831
BING(int)! 668662394 > 667539649, 1122745
1006355562 =? 1073741823, 3154727581 =? 3221225470

请注意,BING(长)和BING(int)都会显示!为什么32位操作失败了,更不用说64位操作了?

在线程回调中,您所做的不仅仅是简单地写或读:

++longValue;
++intValue;

不能保证读写都是原子的。用于确保此操作的原子性。

您是否可以编辑问题以使用工具栏上的“代码示例”格式?这是难以置信的难以阅读…我有它的格式正确,但与制表符,而不是空间和预览最初看起来很棒。当我发现它在发布时完全失败时,我感到震惊。我现在修好了。你能把
longValue
intValue
标记为
volatile
吗?这将消除任何内存障碍问题,而不会影响您尝试测试的行为。long不能标记为volatile。我不希望这些行显式是原子的。我希望写入操作由内存模型保证原子性。这就是我想要证明的。显然,我应该使用Interlocked.Increment(ref intValue或longValue),但这会破坏演示的目的。正如Darin所说,写操作是原子操作,而读+写操作不是原子操作。因此,如果在线程1中读取值5,则将其递增为6,因为它不是原子线程2,可能同时读取了值5,并且已经将其递增为6或更多。因此线程1正在将该值重置回以前的值,解释您看到的行为。同意。您的32位操作系统确实出了问题。或者这台机器只有一个核心。@James:你真的没有抓住要点。运算符++()不是原子的。如果是这样的话,那么实现Interlocked.Increment()将是愚蠢的@James:您不一定在这里看到内存模型问题。您很可能在2 O/S中看到线程调度的差异。正如其他人所说,++操作符不是原子的(请参阅这些注释中Julien的解释)。如果你只是改变你正在使用的3个线程中的任何一个被抢占/唤醒的时间,你可以解释这些间隙——你不一定会在这里看到位剪切。为了好玩,我在我的四核机器(win7/64位)上运行了它,我打赌我得到了数百个BINGs(在x86和任意CPU配置中)
++longValue;
++intValue;