【问题标题】:How does SMP multithreading share memory and interrupts?SMP多线程如何共享内存和中断?
【发布时间】:2010-09-29 23:43:06
【问题描述】:

我正在为我的内核做一些输入缓冲区的工作,我有一些问题。在双核机器上,我知道可以同时运行多个“进程”。我不知道操作系统和各个程序如何保护数据冲突。

关于这个话题我想知道两件事:

(1) 中断发生在哪里?它们是否保证发生在一个核心上而不是另一个核心上,这是否可以用来确保一个核心上的实时操作不会被另一个核心上可以处理的文件 IO 中断? (我从逻辑上假设中断会发生在第一个核心上,但这总是正确的,你怎么知道?或者每个核心都有自己的中断设置?这不会导致每个核心都发生中断吗?内核可以同时对同一个中断做出反应,可能以不同的方式?)

(2) 双核处理器如何处理操作码内存冲突?如果一个核心正在读取内存中的地址,而另一个核心正在写入内存中的同一地址,会发生什么?是抛出异常,还是读取了值? (我假设无论哪种方式写入都可以。)如果读取一个值,是否保证它是冲突时的旧值或新值?

我知道理想情况下应该编写程序以避免这些并发症,但操作系统当然不能指望这种情况,并且需要能够处理此类事件而不会自己窒息。

【问题讨论】:

  • 多处理器操作系统设计/实现不适合胆小的人。 :-)
  • 操作系统设计通常不适合胆小的人,但这当然不会阻止我想要这样做。 ^_^
  • 如果你需要一个最小的例子来测试这些东西:stackoverflow.com/a/33651438/895245

标签: x86 kernel multicore osdev


【解决方案1】:

在 x86 处理器中,这由 APIC 处理。您可以在Intel® 64 and IA-32 Architectures Software Developer's Manual,特别是volume 3,第9章和x2APIC specification中查看详细信息。

如果您不想深入了解所有细节,我将简要介绍一下。

中断可能来自三个不同的来源:

  • 外部引脚(在高达 Core i7 的 Intel 处理器中,您有 LINT0、LINT1、SMI、INIT。我不知道它们在 Core i7 或 AMD 或 Via 处理器中的名称)。
  • 总线事务。这是现代系统中一个线程向另一个线程发送中断的主要方式。它们被称为 IPI - Iinter-P处理器I中断。
  • 内部事件,例如热中断、事件监视器或内部错误。

每个逻辑处理器(SMT 系统中的线程、非 SMT 多核系统中的内核、非 SMT 非多核系统中的处理器)都有一个 APIC。 APIC 控制逻辑处理器如何响应任何此类中断。

简而言之:

SMI 和 INIT 引脚始终分别路由到 SMI 或 INIT。

如果 APIC 被禁用,LINT0 被路由到 INTR,LINT1 被路由到 NMI,并且 IPI 被忽略。

如果已启用:

  • LINT0、LINT1、热事件、事件监视器和错误在 LVT 中都有一个条目(L逻辑 Vector Table)指定它是否被屏蔽,如果没有,它将是什么类型的中断。
  • 处理 IPI。 IPI 包括中断类型(即 INTR、SMI、NMI、INIT、SIPI)和目的地。每个逻辑处理器都有一个 APIC-ID,即 .如果 IPI 的目标与其 ID 匹配,则它处理中断。否则它会忽略它。

如果您想了解有关启用 APIC、LVT 编程、设置 APIC-ID 和发送 IPI 的详细信息,您必须查看我链接到的手册。

【讨论】:

    【解决方案2】:

    操作系统开始设置处理中断的位置。 Linux 对中断进行负载平衡,以便它们可以由两个 CPU 处理。每个中断处理程序都需要获取一个锁,以避免在不同的 CPU 上同时执行相同的处理程序,还可以防止其他内核代码在非中断上下文中运行并访问相同的数据结构。但是,我认为可以在给定 CPU 上绑定给定中断的执行。

    关于问题(2):保证与SMP机器给出的保证基本相同,即不抛出异常,结果取决于谁来执行/将值提交到内存/将值提交到共享先缓存。无论如何,您都不能依赖读取值 - 事实上,所提供的保证远没有您预期的那么强大。

    在 Internet(在 Google 或 Wikipedia 上)了解什么是数据竞争,并从研究如何在 Java 中正确编写多线程代码开始。学习这让我更容易理解 Linux 内核的并发机制。

    或者直接使用C/C++ almost "official" memory model FAQ、Linux 内核源代码树中的 Documentation/memory-barriers.txt 或 Jeremy Manson's post on the issue。 无论如何,我忘了指出您读取的值不一定是由某个处理器实际写入的。对于 32 位值,这是由 32 位写入是原子的事实来保证的。对于 64 位值,这通常是不正确的(我不确定 64 位平台,但由于可移植性的原因,我通常不依赖它)。

    无论如何,如果您发现自己在问这个问题,您可能应该改进代码使用的锁定。在内核中工作,您首先需要编写自己的自旋锁/信号量库来解决这个问题。

    当您说“您的内核”时,您的意思并不清楚,但我认为您实际上不太可能是指“我正在编写的内核”。无论如何,我不会让任何人提出问题 (2) 在我的机器上运行多线程程序 :-)。

    我明白程序应该 最好写成避免这些 各种并发症,但操作系统 当然不能指望,并且会 需要能够处理此类事件 不会自己窒息。

    这个问题的答案是编写用户空间多线程程序时需要知道的。好吧,您不需要知道“您读取的值”的确切答案,但仅仅因为您不能依赖它,即使您为特定处理器编写汇编代码,它也是实现定义的。仅仅因为您不能依赖两个并行线程的相对速度。永远。

    【讨论】:

    • 不,恐怕我确实是指我正在编写的内核。我正在重新发明轮子以在这里了解有关轮子的更多信息,我认为了解内核如何工作的最简单方法是编写一个,男孩是我经历了一次艰难的旅程。 ^_^ 但这是很好的体验,谁知道呢,它最终可能真的有用。
    【解决方案3】:

    IA-32 参考手册将明确回答您的问题。

    我的直觉是两个内核 rx 都会中断,操作系统会对其进行排序。每个内核上可能都有一个设置寄存器,用于指定哪个内核获得哪个中断。

    碰撞。没有保证。更准确地说,研究缓存机制以及它们如何解决一致性问题。

    对于与此相关的其他线程:

    How do interrupts in multicore/multicpu machines work?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-23
      • 2010-12-09
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 2020-06-23
      • 2014-10-01
      • 2012-10-31
      相关资源
      最近更新 更多