Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.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中是原子的,那么为什么我在这里得到不同的值?_C#_.net_Multithreading_Atomic - Fatal编程技术网

C# 如果浮点数上的操作在.NET中是原子的,那么为什么我在这里得到不同的值?

C# 如果浮点数上的操作在.NET中是原子的,那么为什么我在这里得到不同的值?,c#,.net,multithreading,atomic,C#,.net,Multithreading,Atomic,我有一些代码,这是它最简单的形式做如下 float result = RunSimulation(); totalResult += result; 如果我在一个线程中运行它,与在多个线程中运行它相比,我会得到不同的结果。如果我在totalResult加法上加上一个锁,那么我会得到相同的结果,但会付出巨大的性能代价 由于浮点数是32位的,我认为浮点数上的操作保证是原子的,所以我不明白为什么线程化会给我不同的结果 我可以使用ThreadStatic字段来记录总数,然后在线程终止时将它们与锁一起添

我有一些代码,这是它最简单的形式做如下

float result = RunSimulation();
totalResult += result;
如果我在一个线程中运行它,与在多个线程中运行它相比,我会得到不同的结果。如果我在totalResult加法上加上一个锁,那么我会得到相同的结果,但会付出巨大的性能代价

由于浮点数是32位的,我认为浮点数上的操作保证是原子的,所以我不明白为什么线程化会给我不同的结果

我可以使用ThreadStatic字段来记录总数,然后在线程终止时将它们与锁一起添加,所以这不是我要寻找的解决方案,只是一个解释

我编写了一些测试代码,以最简单的形式检查这一点。此代码如下所示,并且每次运行都会产生不同的结果

class Program
{
    static float total;
    static int threadCount;

    static void Main(string[] args)
    {
        while (true)
        {
            total = 0;
            for (int i = 0; i < 10; i++)
                new Thread(ThreadMethod).Start();

            do
            {
                Thread.Sleep(10);
            } while (threadCount > 0);

            Console.WriteLine(total);
            if (Console.ReadKey(true).Key == ConsoleKey.Escape)
                break;
        }
    }

    static void ThreadMethod()
    {
        threadCount++;
        for (int i = 0; i < 100000; i++)
            total = total + 1.234f;

        threadCount--;
    }
}
类程序
{
静态浮点数;
静态int线程数;
静态void Main(字符串[]参数)
{
while(true)
{
总数=0;
对于(int i=0;i<10;i++)
新线程(ThreadMethod).Start();
做
{
睡眠(10);
}而(线程数>0);
控制台写入线(总计);
if(Console.ReadKey(true).Key==ConsoleKey.Escape)
打破
}
}
静态无效线程方法()
{
threadCount++;
对于(int i=0;i<100000;i++)
总计=总计+1.234f;
线程数--;
}
}

读取和写入浮动是原子的,这是。但是,浮动操作不是原子操作。在这种情况下,没有办法使用某种同步


另一方面,您有一个小的争用条件,while可能在任何线程启动之前退出。

x+=y
不是原子操作,它与
x=x+y
相同,因此涉及两次读取和一次写入。读取或写入
float
是原子操作。从整体上看,读和写并不是原子性的。原子性只能保证永远不会读取部分写入的值。其中有些字节已更新,有些字节仍具有旧值。这是一个非常弱的保证,而且不必确保像您正在使用的读-修改-写操作以不可中断的顺序发生,并且内存内容的视图不过时。这里需要使用lock关键字。谢谢。不太担心测试程序中的比赛条件。我敢肯定,过去20年中生产的任何CPU都可以在10毫秒内启动线程。:-)@WillCalderwood我认为这更多的是操作系统的问题,而不是CPU的问题(不确定),但是的,在这里并不重要:)