1

我知道当操作系统/硬件在不同线程的执行之间切换时,它管理存储/恢复每个线程的上下文,但是我不知道很多细节。我的问题是:是否有任何寄存器可用于在线程之间共享信息?在 x86 中?米普斯?手臂?ETC,。linux?视窗?

任何关于如何做到这一点的建议都非常感谢。

4

3 回答 3

1

有一些处理器架构在上下文切换期间不存储某些寄存器。从内存来看,29K 有一些类似的寄存器,它们本质上只是全局变量——gr112 .. gr115从网络上看。现在,这是一台有 192 个物理寄存器的机器,因此它能够承受为这种目的牺牲一些物理寄存器也就不足为奇了。

我知道 x86 和 x86-64 使用“所有寄存器”这一事实,ARM 也是如此。据我所知,MIPS 也没有任何“为用户保留”的寄存器。这适用于 Windows 和 Linux 操作系统。

对于任何具有少量寄存器(小于或等于 32)的处理器,我会说“浪费”寄存器是全局的,只是为了保存一些其他线程/进程可能想要读取的值是资源浪费 - 通用代码如果该寄存器用作编译器可用的通用寄存器,则运行速度会更快。

于 2013-05-23T16:06:05.203 回答
1

如果您正在编写将进入系统的所有代码,您可以将寄存器专用于您想要的任何目的,但受限于任何专用于特定功能的寄存器将无法用于任何其他目的。有一些非常特殊的情况可能值得这样做;这些通常需要(尽管看起来很奇怪)非常简单但需要快速运行的程序。像 gcc 这样的一些编译器可以通过允许程序员指定特定的寄存器来促进这种使用,除非明确要求,否则它生成的代码不应将其用于任何目的。一般来说,因为通过限制编译器可以使用的寄存器数量会降低编译代码的效率,简单地使用静态定义的内存位置在线程之间交换信息会更有效。虽然内存位置的访问速度不如寄存器快,但可以为各种目的保留其中的许多位置,而不会影响编译器优化寄存器使用的能力。

我在 ARM 上看到的使用专用寄存器很有帮助的一种情况是,需要大量方法共享一个公共静态数据结构。指定应始终假定某个寄存器保存指向该数据结构的指针,并且该代码绝不能修改它,从而消除了代码在访问其中的项目之前加载该结构的地址的需要。如果您想在线程之间共享信息,这可能是一种有用的方法,因为访问任意静态位置通常需要相对于 PC 的加载来获取地址,然后加载实际数据;拥有一个专用寄存器将消除其中一个负载。

于 2013-05-23T16:06:43.440 回答
0

乍一看,您的问题似乎很合理。其他人试图直接回答这个问题。首先,我们有两个相当模糊的概念,

  1. 线程
  2. 寄存器

如果你和Ada的人交谈,他们会因为缺乏对linuxposix线程的定义而吓坏了。他们更喜欢Java 的绿色线程,具有非常确定的调度。我认为您的意思是处理器速度快的线程,例如posix线程。

第二个问题是什么是寄存器?对于大多数人来说,它们仅限于在 CPU 指令集中硬编码的 8,16 或 32 个寄存器。通常有可以通过其他方式访问的二类寄存器。主要是它们的速度非常快。

你的问题的反面很常见。如何为每个线程将寄存器设置为不同的值。通用寄存器由编译器使用,编译器的ABI对OS 上下文切换代码非常熟悉。可能不清楚的是,每次线程运行时,堆栈寄存器的高位可能是恒定但每个线程都不同。也就是说每个线程都有自己的栈。

在 ARM Linux 中,使用一个特殊的协处理器寄存器来实现线程本地存储协处理器寄存器的访问速度比通用寄存器慢,但仍然相当快。这将我们带到了进程和线程之间的区别。

线程特有的

一个进程具有完全不同的内存布局。即,mmu页表为不同的进程切换。对于一个线程,寄存器集可能不同,但所有常规内存都是在线程之间共享的。出于这个原因,当你进行线程编程时,会有很多互斥锁。

现在,考虑一个 CPU 缓存。它是超快内存,就像通用寄存器一样。唯一的区别是处理它所需的指令数量。

回答

所有的操作系​​统和 CPU 都已经有了这个!每个线程共享内存并且该内存被缓存从缓存加载两个线程中的全局变量几乎与寄存器访问一样快。由于您建议的线程寄存器只能保存一个指针,因此您需要取消引用它才能访问一些更大的实体。加载一个全局变量几乎一样快,编译器可以自由地将它放在它喜欢的任何寄存器中。编译器也可以在不需要此访问的例程中使用这些寄存器。因此,即使有一个操作系统保留一个通用寄存器在线程之间相同,它只会更快非常小的一组应用程序。

于 2013-05-29T00:20:13.510 回答