.net - 为什么在单个 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}");
}
}
解决方案
当您在单个内核上执行进程时,所有线程都会按顺序工作。调度程序将一些执行时间(称为quantum)分配给第一个线程。当量程到期时,调度程序停止该线程并运行准备运行的下一个线程。等等。这种类型的多任务处理称为抢占式。
现在,当您在单核上运行进程时,仍然有可能获得竞争条件并获得一个Counter
不同于 0 的值。但是,由于这些循环很简单并且运行速度非常快,因此它们很可能在单个内核中执行量子,最多一对。因此,获得比赛条件的机会非常非常低,接近于零。
推荐阅读
- sails.js - 来自数据库适配器的意外错误:`select` 失败(“badConnection”)
- python - 在 Dataframe 上并行化 PySpark 阐述的最佳方法?
- join - 如何在 SAS 的数据集中找到匹配项后创建新变量
- c# - 批量合并(添加和更新)行
- sql - 好与坏以及为什么在 SQL 查询连接中应用复杂查询?
- java - 如何使用 Java 使用 bodyPart.isMimeType("message/rfc822") 读取 .mgs 附件
- laravel - Laravel 按特定列获取下一条/上一条记录
- google-chrome-devtools - Google Chrome DevTools 中的元素选项卡行为不端
- graph - Cypher:在多个路径中循环不同的节点
- google-sheets-api - 在图表中切换行和列