【问题标题】:Cache coherency: Threads vs Cores缓存一致性:线程与核心
【发布时间】:2019-05-22 15:22:09
【问题描述】:

我目前正在研究并发系统,当同时处理多个线程和多个内核时,我对缓存一致性的概念有些困惑。

据我了解的一些假设:

  • 核心有缓存
  • 内核一次可能有多个线程(如果是超线程)
  • 线程是正在处理的单行命令
  • 因此,线程不是物理硬件,线程没有缓存并使用内核的缓存

假设 一个核心有我们有两个线程,x 是一个值为 5 的共享变量。两者都想执行:

my_y = x;

其中my_y 是由两个线程定义的私有变量。现在假设线程 0 执行:

x++;

最后,假设线程 1 现在执行:

my_z = x;

my_z 是另一个私有变量。

我的书是这样说的:

my_z 的值是多少?是五吗?或者是六个?问题是x 有(至少)三个副本:一个在主内存中,一个在线程 0 的缓存中,一个在线程 1 的缓存中。

这是如何工作的? x 怎么至少有三份副本,为什么书中规定每个线程都有自己的缓存?对我来说,运行这两个线程的核心在其缓存中具有 x 的值是有意义的,因此两个线程在“它们的”(共享)缓存中都有值。

换句话说,当x++ 被更新时,核心缓存中的值也会被更新。然后,线程 1 将执行my_z = x;,它仍在内核的缓存中并且是最新的。因此,不会有一致性问题,因为两个线程基本上共享缓存。

这本书可能假设每个内核只有一个线程,但该书之前确实提到了“如果线程数多于内核数”。 “如果线程数多于内核数”是否意味着一个内核有多个线程(超线程),或者是否发生了某种线程调度以使每个内核一次只有一个线程?

即使是这种情况(核心的调度,一个核心一次只能有一个线程),如果一个核心拥有线程0,则执行x++,然后获取试图执行@的线程1 987654334@ 如果我没记错的话,x 的值仍会存在于该内核的缓存中。

额外问题:线程的私有变量如何存储在内存中?它们的存储方式是否与使用时被复制到核心缓存中的任何变量相同?如果是这种情况,如果多个线程正在使用缓存(无论是同时还是调度),那么在内核的缓存中拥有一个私有变量会不会有问题?

根据@biziclop 的要求,本书陈述了以下假设:

  • 我们使用 MIMD 系统,即节点具有相同的架构。 (不过,这本书并没有具体说明这是哪种架构)
  • 我们的程序是 SPMD。因此,我们将编写一个可以使用分支来实现多种行为的程序。
  • 我们假设内核相同,但异步运行。
  • 我们使用 C 语言进行编程,在本节中,我们主要关注 Pthreads。

任何帮助将不胜感激!

【问题讨论】:

  • 不要忘记(在高度优化的代码中)变量通常会在寄存器中存储很长时间,与任何 L1 或 L2 缓存无关。不过,如果您能指定我们正在谈论的语言/架构,那将会有所帮助。
  • 谢谢,@biziclop。我在帖子中添加了更多信息。
  • IMO,如果您不是在学习设计计算机硬件,那么在您的职业生涯中尝试了解超线程的微妙之处可能还为时过早。如果您正在编写将在某些多处理器操作系统下以用户模式运行的代码,那么无论如何您将无法控制哪个内核的哪个“硬件线程”将在任何给定时刻运行您的代码。如果您根据您选择的任何编程语言的“内存模型”编写代码,那么无论操作系统选择哪些硬件资源来运行您的程序线程,它都会正确运行。

标签: multithreading caching concurrency


【解决方案1】:

为什么书中规定每个线程都有自己的缓存?

作者太马虎了。线程没有缓存。运行线程的处理器内核具有缓存。

这本书以前[说]“如果线程多于核心”。 [that] 是否意味着一个核心有多个线程(超线程),或者是否发生了某种线程调度以使每个核心一次只有一个线程?

其中任何一个都可能是真的。我们已经确定作者在语言方面有点草率,因此将这句话从上下文中剔除,无法判断它是在谈论更多的硬件线程而不是内核还是更多的软件线程。

线程的私有变量是如何存储在内存中的?

进程中的所有线程都看到完全相同的虚拟地址空间。从最广泛的意义上来说,“private”只是简单地描述了一个只被一个线程使用的内存位置,而为什么这个位置只被一个线程使用并不重要。

在更狭义的意义上,每个线程都有一个函数激活记录堆栈(也称为“调用堆栈”),其中包含所有活动函数调用的参数和局部变量。在许多编程语言中,一个线程不可能与任何其他线程共享其 args 或 locals,因此这些内存位置自动是“私有的”。在其他编程语言中,可能共享 arg 或 local,但程序员必须编写显式代码才能共享它,无论如何,这可能是个坏主意。

如果多个线程正在使用缓存(无论是同时还是调度),那么在内核的缓存中拥有一个私有变量会不会有问题?

当两个不同的内存位置都散列到同一个缓存位置时,这称为冲突。是的!碰撞有时会发生。如果某个缓存行包含变量 X,而线程 T 想要访问恰好使用相同缓存行的变量 Y,则内存系统将让线程 T 等待,同时从主内存中获取数据。

这种现象也被称为“错误共享”(通常是当它成为一个问题时),您可以通过 Google 搜索策略来避免它如果以及何时您确定它实际上会降低你的程序。

【讨论】:

  • 完美的解释。谢谢。
  • 一些作者可能会使用“线程缓存”,其更广泛的含义是线程可能主动缓存全局内存视图的任何内容。在 Java 中,允许线程保留非易失性变量的私有副本,即使在看到变量的更新值后也不对其进行更新:不存在“连贯性”。
猜你喜欢
  • 2011-02-28
  • 1970-01-01
  • 2011-12-24
  • 1970-01-01
  • 1970-01-01
  • 2013-01-06
  • 1970-01-01
  • 2012-04-04
相关资源
最近更新 更多