多个进程的线程实际上是同时运行的吗?

4
在一个带有2个物理x86/amd64处理器(P0+P1)的Windows操作系统中,运行着2个进程(A+B),每个进程都有两个线程(T0+T1)。是否可能(甚至是常见的)看到以下情况: P0:A:T0P1:B:T0 同时运行, 然后,在1个(或2个?)上下文切换之后, P0:B:T1P1:A:T1 同时运行。
简而言之,我想知道在多处理器机器上,操作系统是否可以自由地安排来自任何进程的任何线程在任何时间运行,而不考虑其他进程的其他线程已经在运行什么。
编辑:为了澄清这个愚蠢的例子,假设进程A的线程A:T0具有与处理器P0的亲和性(A:T1具有与P1的亲和性),而进程B的线程B:T0具有与处理器P1的亲和性(B:T1具有与P0的亲和性)。这些处理器可能是核心或插座无关紧要。
是否有一流的进程上下文切换概念?Perfmon在Thread对象下显示上下文切换,但在Process对象下没有任何东西。

请注意,典型的操作系统并不太关心两个核心在物理上有多远:它们可以在同一芯片上、在同一插槽中的两个芯片上,甚至在不同的插槽中。至少,在这两个核心共享单个非统一内存的情况下是如此。NUMA架构则是另一种情况。 - MSalters
有趣的是,我没有考虑到超线程,但是如果操作系统无法区分,那么在单插槽、单核心、超线程处理器上,这两个线程可能属于不同的进程吗? - Jono
2个回答

6
是的,这是可能的,而且经常发生。
操作系统会尽量避免在CPU之间切换一个线程(你可以通过设置线程的首选处理器来使其更加努力,或者通过亲和力将其锁定到单个处理器)。从这个角度来看,Windows进程本身不是一个执行单元,而只是它的线程的上下文。
编辑(进一步澄清):
没有什么像“进程上下文切换”的东西。基本上,操作系统调度程序通过(非常适应性的)循环轮询算法将线程分配给任何空闲的处理器/核心(根据亲和力),如果“前一个”处理器不可用,则立即分配给其他处理器,不考虑进程(这意味着多线程进程可以窃取更多的CPU资源)。
这种“跳跃”可能看起来很昂贵,因为至少L1(有时是L2)缓存是每个核心的(除了不同的插槽/包处理器),但它仍然比等待“正确”的处理器和无法进行复杂的负载平衡(这种“跳跃”方案使其成为可能)造成的延迟更便宜。这可能不适用于NUMA架构,但还涉及更多考虑因素(例如,将所有内存分配适应于线程和处理器,并尽可能避免状态/内存共享)。
至于亲和力:你可以为每个线程或每个进程设置亲和力掩码(这将取代所有进程线程的设置),但操作系统强制至少一个逻辑处理器与每个线程关联(你永远不会得到零掩码)。
进程的默认亲和力掩码从其父进程继承而来(这使您可以创建针对有问题的旧版可执行文件的单核加载程序),线程从它们所属的进程继承掩码。
你不可以将线程的亲和力设置为进程之外的处理器,但可以进一步限制它。
任何线程默认情况下都会在可用的逻辑处理器之间跳跃(特别是如果它放弃,调用内核等),即使它设置了首选处理器,但只有在必要时才会跳跃,但它不会跳跃到其亲和力掩码之外的处理器(这可能会导致相当大的延迟)。
我不确定调度程序是否看到物理和超线程处理器之间的差异,但即使它不看到(我假设),后果在大多数情况下也不会引起关注,即多个线程共享物理或逻辑处理器的线程数相同,则不应该有太大区别。无论如何,这种情况下可能会有一些缓存抖动的报告,主要是在高性能的重度多线程应用程序中,例如SQL服务器或.NET和Java VM,这些应用程序可能会受益于关闭超线程技术。

我相信这比那要复杂一些。单个进程的所有线程共享相同的虚拟地址空间,除了共享内存外,不会与另一个进程重叠。这也意味着操作系统将单个进程的线程保留在单个核心上是有益的 - 减少重新加载的上下文。 - MSalters
@MSalters:我同意当线程来自不同的进程时,切换上下文必须会有一些额外的成本,但我不认为操作系统自动将线程保持在单个核心上是一个好的选择,特别是随着可用处理器数量的增加。有趣的是,量化从一个虚拟地址空间切换到另一个空间的额外成本,超过线程切换的成本。 - Jono
感谢您的编辑,维克多。非常有启发性。我怀疑很少有并发问题不能用“实际上,它稍微更加复杂”来说明......但像这样的良好近似真相将指引我朝着正确的方向前进。 - Jono

2

我基本同意前一个答案,但情况更为复杂。

虽然进程不是执行单元,但属于同一进程的线程应该被不同对待。原因如下:

  1. 具有相同的地址空间。这意味着,在这些线程之间切换上下文时,无需设置地址转换寄存器。
  2. 同一进程的线程更有可能访问相同的内存。

(2)对缓存状态有很大影响。如果线程读取相同的内存位置,则它们重用L2缓存,因此整个过程加速。但也有缺点:一旦线程更改内存位置,则该地址在两个处理器的L2缓存中都会失效,因此另一个处理器也会使其缓存失效。

因此,同时运行同一进程的线程(在不同的处理器上)有利有弊。顺便说一下,这种情况有一个名称:“团体调度”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接