static long x;
const int count = 1000000;
static void ThreadProc()
{
for (int i = 0; i < count; ++i)
{
x = 0;
var result = x;
if (result != 0 && result != -1)
Console.WriteLine("Opps 1");
}
}
static void Main(string[] args)
{
var task = Task.Run(new Action(ThreadProc));
for (int i = 0; i < count; ++i)
{
x = -1;
var result = x;
if (result != 0 && result != -1)
Console.WriteLine("Opps 2");
}
task.Wait();
}
该程序在 x64 中正确运行,但在 x86 中在 writeline 中显示文本。结果 var Hold 值为 -4294967296 或 4294967296,x 仍为 0 或 -1。我不确定它是最大/最小还是临时值。当我改变时
static long x;
至
static int x;
问题已经解决了。
我确实知道我们应该锁定 x 变量。但我想知道为什么结果变量得到错误的值。
最佳答案
十进制值 -4294967296
的 64 位十六进制为 0xffffffff00000000
。值 -1
十进制为 64 位十六进制的 0xffffffffffffffff
。当然,值 0
是 0x0000000000000000
。请注意,您看到的错误值是 -1
的一半和 0
的一半。
在您的 32 位程序中,long
(64 位)不会以原子方式写入。相反,它被写成两个 32 位 block 。同样,64 位值不会以原子方式读取,而是以两个 32 位片段的形式读取。
有时,您所显示的代码的一个线程会在写入过程中被另一个线程捕获。向变量写入两个 0x00000000
部分,或两个 0xffffffff
部分(取决于捕获哪个线程)。任何一个线程的非原子行为都可能导致这种情况,但是当然两个线程的行为都是非原子的(写入和读取),因此根据每个线程在其竞争中的位置,您可以“责怪”两者都有问题。
当您将变量类型切换为 int
时,您会将数据大小从 64 位更改为 32 位,这在 x86 程序中可以原子方式写入和读取。因此,两个线程都不能在写入或读取过程中被捕获。
参见相关讨论:
C# thread safe static member
关于c# - 使用并行任务时x86和x64的数据类型有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30339797/