我记得在我上大学的一门课程中,我最喜欢的竞赛条件示例之一是一个简单的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上同时运行?
发布于 2011-04-03 17:53:06
是的,双核CPU的引入使得大量具有潜在线程竞争的程序迅速失败。单核CPU由调度器执行多任务,在线程之间快速切换线程上下文。它消除了与过时的CPU缓存相关联的一类线程错误。
不过,您给出的示例在单个核上也可能失败。当线程调度程序中断线程时,就像它在寄存器中加载变量的值一样,以增加它。它不会经常失败,因为调度程序中断线程的可能性并不大。
有一个操作系统功能,允许这些程序一瘸一拐地前进,而不是在几分钟内崩溃。称为“处理器亲和力”,可作为Windows上start.exe的亲和命令行选项,SetProcessAfinityMask()在winapi中。检查助手方法的互锁类,这些方法原子地增加和减少变量。
发布于 2011-04-03 17:40:00
你还会有比赛状态-这一点也改变不了。假设两个核心同时执行增量--它们都加载相同的值,增量到相同的值,然后存储相同的值.因此,这两个操作的整体增量将是1而不是2。
与内存模型有关的潜在问题还有其他原因--步骤1可能不会真正检索i的最新值,而步骤3可能不会以其他线程可以看到的方式立即写入i的新值。
基本上,这一切都变得非常棘手--这就是为什么在访问共享数据时使用同步或者使用真正知道自己在做什么的专家编写的无锁高级抽象通常是一个好主意。
发布于 2011-04-03 17:59:52
首先,双处理器和双核没有真正的效果。双核处理器在芯片上仍然有两个完全独立的处理器。它们可能共享一些缓存,并共享到内存/外围设备的公共总线,但是处理器本身是完全独立的。(双线程的单代码,如超线程)是第三种变体--但每个虚拟处理器也有一组寄存器。这两个处理器共享一组执行资源,但它们保留完全独立的寄存器集。
第二,真正有趣的情况只有两种:一条执行线程和其他所有东西。一旦有了多个线程(即使所有线程都运行在单个处理器上),您就会遇到相同的潜在问题,就像在一个拥有数千个处理器的大型机器上运行一样。现在,当代码在更多的处理器上运行时(最多已经创建了线程),您可能会看到问题更快地显现出来,但是问题本身根本没有/不会改变。
从实际的角度来看,拥有更多的核从测试的角度来说是有用的。考虑到在一个典型操作系统上切换任务的粒度,编写几年不会在单个处理器上显示问题的代码非常容易,当您在两个或两个物理处理器上运行它时,这些代码会在几个小时甚至几分钟内崩溃和烧毁。问题并没有真正改变--只是当你有更多的处理器时,它更有可能更快地出现。
最终,竞争条件(或死锁、活锁等)是关于代码的设计,而不是它运行的硬件。硬件可以改变您需要采取哪些步骤来执行所涉及的条件,但是相关的差异与处理器的简单数量没有多大关系。相反,它们是关于这样的事情:当您拥有的不仅仅是一台具有多个处理器的机器,而是具有完全独立的地址空间的多台机器时所做的让步,所以您可能需要采取额外的步骤来确保当您将一个值写入内存时,它在其他无法直接看到该内存的计算机上对CPU是可见的。
https://stackoverflow.com/questions/5531214
复制相似问题