.net 为什么在单CPU内核中运行多线程会变得线程安全?

.net 为什么在单CPU内核中运行多线程会变得线程安全?,.net,multithreading,concurrency,.net,Multithreading,Concurrency,在多线程编程中,我们知道当多线程访问共享静态变量时,无论有多少个CPU核,都会出现争用条件和线程安全问题。喜欢这个链接 我想知道在不同数量的CPU核下运行多线程和竞争条件代码需要多少时间(这只是自学,我想知道,尽管这毫无意义) 我编写了下面一个.NET控制台示例代码,它创建了两个线程 thread1将在循环中执行int.MaxValue次数,并为share静态变量增加一次 thread2将在循环中执行int.MaxValue次数,并将为share静态变量减少一次 当我使用Process.GetC

在多线程编程中,我们知道当多线程访问共享静态变量时,无论有多少个CPU核,都会出现争用条件和线程安全问题。喜欢这个链接

我想知道在不同数量的CPU核下运行多线程和竞争条件代码需要多少时间(这只是自学,我想知道,尽管这毫无意义)

我编写了下面一个.NET控制台示例代码,它创建了两个线程

thread1将在循环中执行int.MaxValue次数,并为share静态变量增加一次

thread2将在循环中执行int.MaxValue次数,并将为share静态变量减少一次

当我使用
Process.GetCurrentProcess().ProcessorAffinity
设置此进程需要多个处理器时,由于竞争条件问题,share静态变量在执行完成后不会变为0,而是一个任意值

但是我发现当通过
Process.GetCurrentProcess().ProcessorAffinity=(IntPtr)0b00010001将此进程设置为仅使用一个逻辑进程时
Process.GetCurrentProcess().ProcessorAffinity=(IntPtr)0B00010
Process.GetCurrentProcess().ProcessorAffinity=(IntPtr)0b00010100

在这样的环境中,只有一个逻辑处理器来执行这个多线程程序,尽管出现争用情况,但总体执行结果似乎是线程安全的。因为无论执行多少次,share静态变量Counter的最终结果总是0

我不知道为什么会出现这种现象,有人能解释一下:

在.NET CLR下,指定只能使用单个CPU内核,并且在执行结束后,它将具有线程安全功能,这意味着计数器此共享静态变量将始终为0

我录制了整个测试过程,录制的视频就在这里

[更新]

我已使用Visual Studio 2019的.net反汇编程序检查以下C#代码中的IL代码:

for (int i = 0; i < int.MaxValue; i++)
{
    Counter = Counter + 1;
}
for(int i=0;i
{
对于(int i=0;i
{
对于(int i=0;i
当您在单个内核上执行进程时,所有线程都按顺序工作。调度程序为第一个线程分配一些执行时间(称为quantum)。当quantum过期时,调度程序停止该线程并运行准备运行的下一个线程。等等这种类型的多任务处理称为


现在,当您在单个内核上运行进程时,仍然可以获得竞争条件,并为
计数器
获取一个不同于0的值。然而,由于这些循环很简单,运行速度也很快,它们很可能在一个量子点内执行,最多一对量子点。因此,获得竞争条件的机会非常非常低,接近于零。

当您在单个内核上执行进程时,所有线程都会按顺序工作。调度程序为第一个线程分配一些执行时间(称为quantum)。当quantum过期时,调度程序停止该线程并运行准备运行的下一个线程。等等这种类型的多任务处理称为


现在,当您在单个内核上运行进程时,仍然可以获得竞争条件,并为
计数器
获取一个不同于0的值。然而,由于这些循环很简单,运行速度也很快,它们很可能在一个量子点内执行,最多一对量子点。因此,获得竞争条件的机会非常非常低,接近于零。

虽然循环很简单,但会执行多次。在我的计算机上,完成整个循环(通过单线程)大约需要3~4秒。但是,当我改为使用多个CPU核时,cotter的值将不会为零,并且仅在单个CPU核上。这种奇怪的现象使我很难理解。我试图将循环数修改为int.MaxValue的50倍,这使得这两次执行大约需要580秒才能完成。结果是共享静态变量计数器值为0,正如我所说的:有可能获得竞争条件,但机会很低。虽然循环很简单,但它将被执行多次。在我的计算机上,完成整个循环(通过单线程)大约需要3~4秒。但是,当我改为使用多个CPU核时,cotter的值将不会为零,并且仅在单个CPU核上。这种奇怪的现象使我很难理解。我试图将循环数修改为int.MaxValue的50倍,这使得这两次执行大约需要580秒才能完成。结果是共享的静态变量计数器值为0,正如我所说的:有可能获得竞争条件,但可能性很低。