multithreading - 双CPU机器上的线程合作

标签 multithreading race-condition context-switch

我记得在我上大学的一门类(class)中,我最喜欢的竞态条件示例之一是其中一个简单的main()方法启动了两个线程,其中一个线程将共享(全局)变量增加了一个,另一个减少了它。伪代码:

static int i = 10;

main() {
    new Thread(thread_run1).start();
    new Thread(thread_run2).start();
    waitForThreads();
    print("The value of i: " + i);
}

thread_run1 {
    i++;
}

thread_run2 {
    i--;
}

然后,教授问了10亿亿兆亿次运行后i的值(value)是什么。 (如果基本上不是10,则为零。)不熟悉多线程系统的学生回答100%的时间,print()语句始终将i报告为10。

这实际上是不正确的,因为我们的教授证明了每个增量/减量语句实际上都是(汇编为)3个语句:
1: move value of 'i' into register x
2: add 1 to value in register x
3: move value of register x into 'i'

因此,i的值可以是9、10或11。(我不再赘述)。

我的问题:

我的理解是,物理寄存器集是特定于处理器的。在使用双CPU机器时(请注意双核和双CPU之间的区别),每个CPU是否都有自己的一组物理寄存器?我以为答案是肯定的。

在单CPU(多线程)计算机上,上下文切换允许每个线程拥有自己的虚拟寄存器集。由于双CPU机器上有两个物理寄存器集,因此这不可能导致更多的竞争情况,因为您实际上可以使两个线程同时运行,而不是在单个虚拟机上同时进行“虚拟”同步运行。 CPU机? (引用每个上下文开关保存/恢复寄存器状态的事实,进行虚拟同时操作。)

更具体地说-如果您是在8 CPU的计算机上运行此程序,那么每个CPU都有一个线程,是否消除了竞争条件?如果将此示例扩展为使用8个线程,则在双CPU机器(每个CPU具有4个内核)上,竞争条件的可能性会增加还是减少?操作系统如何防止汇编指令的step 3在两个不同的CPU上同时运行?

最佳答案

是的,双核CPU的引入使大量具有潜在线程争用的程序迅速失败。通过调度程序,单核CPU可以执行多任务,从而在线程之间快速切换线程上下文。这消除了与过时的CPU缓存相关的一类线程错误。

您给出的示例也可能在单个内核上失败。当线程调度程序中断线程时,就像线程将变量的值加载到寄存器中一样,以使其递增。只是不会几乎不那么失败,因为调度程序中断线程的几率并不大。

有一个操作系统功能,可以使这些程序始终运行,而不会在几分钟之内崩溃。称为“处理器相似性”,可作为Windows上start.exe的AFFINITY命令行选项,winapi中的SetProcessAfinityMask()使用。查看Interlocked类以获取自动增加和减少变量的辅助方法。

关于multithreading - 双CPU机器上的线程合作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5531214/

相关文章:

javascript - Ajax 调用的 Angular 1 服务的竞争条件

task - 线程池和上下文切换(任务)?

java - 我可以将 PriorityBlockingQueue 与多个线程一起使用吗?

c++ - Windows 上的快速计数信号量?

ios - NSRunLoop的runMode :beforeDate: - the correct approach for setting the "beforeDate"

C# 进程 - 完成前暂停或 sleep

c - 一旦我们发出了条件变量的信号,我们会继续执行原始线程吗?

c++11 - 为什么 ThreadSanitizer 会报告这个无锁示例的竞争?

linux - 如何理解 "__swtich_ to"在 ARM linux 中的上下文切换功能

linux-kernel - CPU 在 X86 上从内核模式切换到用户模式 ​​: When and How?