我记得在我上大学的一门课程中,我最喜欢的竞争条件示例之一是一个简单的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--;
}
教授接着问i
一百万亿次运行后的价值是多少。(本质上,如果它永远不会是 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 上同时运行?