|
|
1
142
这不是对问题的直接回答,而是对出现在评论中的问题的回答。本质上,问题是硬件对多线程操作提供了什么支持。
Nicholas Flynt had it right
,至少关于x86。在多线程环境(超线程、多核或多处理器)中
引导线程
此机制允许每个线程从不同的地址执行代码。所需要的只是软件支持每个线程设置自己的表和消息队列。操作系统使用 那些 就实际的程序集而言,正如Nicholas所写,单线程或多线程应用程序的程序集之间没有区别。每个逻辑线程都有自己的寄存器集,因此写入:
只会更新
|
|
2
75
Intel x86最小可运行裸机示例Runnable bare metal example with all required boilerplate . 所有主要部分如下。 在Ubuntu15.10QEMU2.3.0和Lenovo ThinkPad T400上测试 real hardware guest 这个 Intel Manual Volume 3 System Programming Guide - 325384-056US September 2015
关于那个密码:
处理器之间的共享状态8.7.1“逻辑处理器的状态”表示:
Intel超线程比单独的内核具有更大的缓存和管道共享: https://superuser.com/questions/133082/hyper-threading-and-dual-core-whats-the-difference/995858#995858 Linux内核4.2
主初始化操作似乎位于
ARM最小可运行裸金属示例在这里,我为QEMU提供了一个最小的可运行ARMv8 aarch64示例:
在这个例子中,我们将CPU 0放在一个spinlock循环中,它只在CPU 1释放spinlock时退出。 在自旋锁之后,CPU 0然后执行 semihost exit call 这让QEMU辞职了。
ARM: Start/Wakeup/Bringup the other CPU cores/APs and pass execution start address? 这个 upstream version 也有一些调整,使其在gem5上工作,所以您也可以试验性能特性。
本文档提供了一些关于使用ARM同步原语的指导,然后您可以使用这些原语在多个核心上做有趣的事情: http://infocenter.arm.com/help/topic/com.arm.doc.dht0008a/DHT0008A_arm_synchronization_primitives.pdf 在Ubuntu 18.10,GCC 8.2.0,Binutils 2.31.1,QEMU 2.12.0上测试。 前面的例子唤醒了辅助CPU,并使用专用指令执行基本的内存同步,这是一个很好的开始。
POSIX
这些是使用Linux内核或其他操作系统的一些好理由:-) Userland内存同步原语尽管线程启动/停止/管理通常超出了userland的范围,但是您可以使用userland线程的汇编指令来同步内存访问,而无需潜在的更昂贵的系统调用。
更微妙的语义在 lock free data structures ,在某些情况下可以提供性能优势。要实现这些,您可能需要了解不同类型的内存障碍: https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/ https://www.boost.org/doc/libs/1_63_0/doc/html/lockfree.html
这样的userland指令似乎也用于实现Linux
系统调用名称本身意味着“快速用户空间XXX”。 这里是一个最小的无用的C++ X86Y64/AARCH64示例,内联汇编说明了这些指令的基本用法,主要用于娱乐:
由此我们可以看到x86锁前缀/aarch64
在Ubuntu19.04AMD64和QEMUaarch64用户模式下测试。 |
|
|
3
42
据我所知,每个“核心”都是一个完整的处理器,有自己的寄存器集。基本上,BIOS在一个内核运行时启动,然后操作系统可以通过初始化其他内核并将它们指向要运行的代码等方式“启动”其他内核。 同步是由操作系统完成的。通常,每个处理器为操作系统运行不同的进程,因此操作系统的多线程功能负责决定哪个进程可以接触哪个内存,以及在内存冲突的情况下应该做什么。 |
|
|
4
38
|
|
|
5
10
您不需要知道任何关于x86的具体信息,就可以使它生成在所有核心上高效运行的代码。 正确地 您可能需要了解一些关于x86的知识,以使它生成在x86上高效运行的代码。 你还可以学习其他一些东西:
您应该考虑编译器是否应该自动并行,或者编译器编译的应用程序的作者是否需要在其程序中添加特殊语法或API调用以利用多个内核。 |
|
|
6
9
每个核心从不同的内存区域执行。你的操作系统将在你的程序中指向一个核心,核心将执行你的程序。您的程序将不知道有多个内核或它正在哪个内核上执行。 也没有仅对操作系统可用的附加指令。这些核与单核芯片相同。每个核心运行操作系统的一部分,该部分将处理与用于信息交换的公共内存区域的通信,以找到下一个要执行的内存区域。 More about multicores and multiprocessors 在Embedded.com上有很多关于这个话题的信息。。。这个话题很快就复杂了! |
|
|
7
5
|
|
|
8
3
这根本不是在机器指令中完成的;核心假装是不同的CPU,并且没有任何特殊的能力相互交谈。他们有两种交流方式:
http://www.cheesecake.org/sac/smp.html 是一个很好的参考与愚蠢的网址。 |
|
|
9
1
单线程应用程序和多线程应用程序之间的主要区别在于前者有一个堆栈,后者每个线程有一个堆栈。由于编译器将假定数据和堆栈段寄存器(ds和ss)不相等,因此生成的代码有些不同。这意味着,通过默认为ss寄存器的ebp和esp寄存器的间接寻址也不会默认为ds(因为ds!=不锈钢)。相反,通过默认为ds的其他寄存器的间接寻址不会默认为ss。
其他多线程代码可能涉及在程序的不同部分运行的不同线程。这种类型的编程不需要同样的调整,因此更容易学习。 |
|
|
10
0
与之前的单处理器变体相比,在每个支持多处理的体系结构中添加的是内核之间同步的指令。此外,您还有处理缓存一致性、刷新缓冲区和操作系统必须处理的类似低级操作的说明。在同步多线程体系结构(如IBM POWER6、IBM Cell、Sun Niagara和Intel“超线程”)的情况下,您还倾向于看到在线程之间设置优先级的新指令(如设置优先级和在无事可做时显式生成处理器)。 但是基本的单线程语义是相同的,您只需添加额外的工具来处理与其他内核的同步和通信。 |