首页 > 解决方案 > 为什么在单个 CPU Core 中运行多线程变得线程安全?

问题描述

在多线程编程中,我们知道当多线程访问共享静态变量时,无论有多少 CPU 内核,都会出现竞争条件并出现线程安全问题。像这个链接一样,单处理器环境可以防止竞争条件吗?.

我想知道在不同数量的CPU Cores下运行多线程和竞争条件代码需要多少时间(这只是自学,我想知道,虽然这没有意义)

我按照 .NET Console 示例代码编写,它创建了两个线程。

thread1 将在循环中执行 int.MaxValue 次,并将增加一个共享静态变量。

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

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

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

在这样的环境下,只有一个逻辑处理器来执行这个多线程程序,虽然出现了竞态条件,但整体的执行结果似乎是线程安全的。因为不管我执行多少次,share静态变量Counter,最终的结果总是0。

不知道为什么会出现这种现象,谁能帮忙解释一下:

在.NET CLR下,规定只能使用单个CPU Core,并且在执行结束后会有线程安全特性,也就是说Counter这个共享静态变量永远为0

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

[更新]

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

for (int i = 0; i < int.MaxValue; i++)
{
    Counter = Counter + 1;
}

反汇编代码底部的绿色区域应该会产生竞态条件,这样就会在任意数量的 CPU Cores 下执行,并且执行周期数足够了,就会出现问题。

在此处输入图像描述

    class Program
    {
        public static long Counter = 0;
        static void Main(string[] args)
        {
            Process.GetCurrentProcess().ProcessorAffinity =
                (IntPtr)0b00010001;

            Thread thread1 = new Thread(x =>
            {
                for (int i = 0; i < int.MaxValue; i++)
                {
                    Counter = Counter + 1;
                }
            });
            Thread thread2 = new Thread(x =>
            {
                for (int i = 0; i < int.MaxValue; i++)
                {
                    Counter = Counter - 1;
                }
            });
            thread1.Start(); thread2.Start();
            thread1.Join(); thread2.Join();
            Console.WriteLine($"Result={Counter}");
        }
    }

标签: .netmultithreadingconcurrency

解决方案


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

现在,当您在单核上运行进程时,仍然有可能获得竞争条件并获得一个Counter不同于 0 的值。但是,由于这些循环很简单并且运行速度非常快,因此它们很可能在单个内核中执行量子,最多一对。因此,获得比赛条件的机会非常非常低,接近于零。


推荐阅读