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的问题(不确定),但是的,在这里并不重要:)