曾几何时,为了编写x86汇编程序,你会得到一条说明"加载EDX寄存器的值为5","递增EDX"寄存器等的指令.
对于具有4个核心(甚至更多)的现代CPU,在机器代码级别上它看起来就像有4个独立的CPU(即只有4个不同的"EDX"寄存器)?如果是这样,当你说"递增EDX寄存器"时,是什么决定了哪个CPU的EDX寄存器递增?现在x86汇编程序中是否存在"CPU上下文"或"线程"概念?
核心之间的通信/同步如何工作?
如果您正在编写操作系统,那么通过硬件公开哪种机制可以让您在不同的内核上安排执行?这是一些特殊的特权指示吗?
如果您正在为多核CPU编写优化编译器/字节码VM,那么您需要具体了解x86,以使其生成能够在所有内核中高效运行的代码?
对x86机器代码进行了哪些更改以支持多核功能?
一般地,对于int num,num++(或++num),作为读-修改-写操作中,是不是原子.但我经常看到编译器,例如GCC,为它生成以下代码(在这里尝试):
由于第5行对应于num++一条指令,我们可以得出结论,在这种情况下num++ 是原子的吗?
如果是这样,是否意味着如此生成num++可以在并发(多线程)场景中使用而没有任何数据争用的危险(例如,我们不需要制作它,std::atomic<int>并强加相关成本,因为它是无论如何原子)?
UPDATE
请注意,这个问题不是增量是否是原子的(它不是,而且是问题的开头行).它是否可以在特定场景中,即在某些情况下是否可以利用单指令性质来避免lock前缀的开销.而且,作为公认的答案约单处理器的机器,还有部分提到这个答案,在其评论和其他人谈话解释,它可以(尽管不是C或C++).
有人可以向我推荐一些文档来说明多CPU,多核和超线程之间的区别吗?我总是对这些差异以及不同场景中每个架构的优缺点感到困惑.
编辑:这是我在网上学习并从别人的评论中学习后的当前理解; 有人可以评论评论吗?
乔治,提前谢谢
软件线程,硬件线程和Java线程有什么区别?
软件线程,Java线程和硬件线程是独立的还是相互依赖的?我问这个是因为,我知道Java线程是在jvm(java.exe)的进程内创建的.
这些不同的进程是否在不同的硬件线程上执行也是如此?
在大多数处理器中,为什么L1缓存的大小小于L2缓存的大小?
我正在使用多个线程在C中实现图像过滤操作,并使其尽可能优化.我有一个问题:如果一个内存被thread-0访问,并且如果同一个内存被thread-1访问,它是否会从缓存中获取它?这个问题源于这两个线程可能运行到CPU的两个不同核心的可能性.所以另一种方法是:所有内核是否共享相同的公共缓存?
假设我有如下的内存布局
int输出[100];
假设有2个CPU核心,因此我产生两个线程同时工作.一种方案可以是将内存分成两个块,0-49和50-99,并让每个线程在每个块上工作.另一种方法是让线程0在偶数索引上工作,比如0 2 4等等.而另一个线程工作在奇数索引上,比如1 3 5 ......这个后来的技术更容易实现(特别是对于3D)数据)但我不确定我是否可以通过这种方式有效地使用缓存.
单个进程中的两个不同线程可以通过读取和/或写入来共享公共存储器位置.
通常,这种(有意)共享是使用lockx86上的前缀使用原子操作实现的,该前缀对于lock前缀本身(即,无竞争成本)具有相当广为人知的成本,并且当实际共享高速缓存行时还具有额外的一致性成本(真或假共享).
在这里,我对生产 - 消费者成本感兴趣,其中单个线程P写入内存位置,另一个线程`C从内存位置读取,都使用普通读取和写入.
在同一个套接字上的不同内核上执行此类操作的延迟和吞吐量是多少,并且在最近的x86内核上在同一物理内核上执行兄弟超线程时进行比较.
在标题中,我使用术语"超级兄弟"来指代在同一核心的两个逻辑线程上运行的两个线程,以及核心间兄弟,以指代在不同物理核心上运行的两个线程的更常见情况.
在单核计算机上,一次执行一个线程.在每个上下文切换上,调度程序检查要调度的新线程是否与前一个线程处于同一进程中.如果是这样,则不需要对MMU(页面表)进行任何操作.在另一种情况下,需要使用新的流程页表更新页表.
我想知道多核计算机上是怎么发生的.我猜每个核心上都有一个专用的MMU,如果同一进程的两个线程同时在2个核心上运行,则每个核心的MMU只需引用相同的页面表.这是真的 ?你能指点我对这个问题的好的参考吗?
看着经过一大堆 的 其他 问题 和 他们的 答案,我得到的印象是有什么在C“挥发性”关键字表示正好没有广泛的协议。
即使标准本身似乎也不够清晰,以至于每个人都无法理解其含义。
除其他问题外:
总结一下问题,似乎(经过大量阅读)“ volatile”保证了类似的结果:该值将不但从/向寄存器,而且至少向内核的L1缓存中读/写,其顺序与读/写出现在代码中。但这似乎没有用,因为在同一线程内从寄存器中读取/写入寄存器已经足够,而与L1缓存进行协调并不能保证与其他线程进行协调。我无法想象仅与L1缓存进行同步的重要性。
用途1
唯一广泛同意使用volatile的似乎是旧的或嵌入式系统,其中某些内存位置通过硬件映射到I / O功能,例如内存中的某个位(直接在硬件中)控制灯光。 ,或内存中的某个位告诉您键盘键是否按下(因为它是通过硬件直接连接到键的)。
看来,“用1”不移植的代码,其目标包括多核系统发生。
USE 2
与“ use 1”没什么不同,是可由中断处理程序(可以控制灯光或存储来自按键的信息)随时读取或写入的内存。但是为此已经存在一个问题,即取决于系统,中断处理程序可能会在 具有自己的内存缓存的不同内核上运行,并且“ volatile”不能保证所有系统上的缓存一致性。
因此,“使用2”似乎超出了“易失性”所能提供的范围。
用途3
我看到的唯一其他无可争议的用途是防止通过指向编译器未意识到的同一内存的不同变量的不同变量对访问进行错误优化。但这可能只是无可争议的,因为人们没有在谈论它-我只看到其中一个提及。而且我认为C标准已经认识到“不同”的指针(例如指向函数的不同args)可能指向同一项目或附近的项目,并且已经指定编译器必须生成即使在这种情况下也可以工作的代码。但是,我无法在最新的标准(500页!)中快速找到此主题。
那么“使用3”也许根本不存在?
因此,我的问题是:
在多核系统的可移植C代码中,“ volatile”是否可以保证任何东西?
浏览最新标准后,答案似乎至少是非常有限的:
1.该标准针对特定类型“ volatile sig_atomic_t”反复指定特殊处理。但是该标准还说,在多线程程序中使用信号功能会导致不确定的行为。因此,该用例似乎仅限于单线程程序与其信号处理程序之间的通信。
2.该标准还为setjmp / longjmp指定了“ volatile”的明确含义。(在其他问题和答案中给出了重要示例代码)。
因此,更精确的问题变成了:
除了(1)允许单线程程序从其信号处理程序接收信息之外,还是(2)允许setjmp,“ volatile”对于多核系统的便携式C代码是否有任何保证?代码以查看在setjmp和longjmp之间修改的变量?
这仍然是一个是/否问题。
如果为“是”,那么最好显示一个无错误的可移植代码示例,如果省略了“ volatile”,则该示例会出现错误。如果为“ no”,那么我认为对于多核目标,在这两种非常特殊的情况下,编译器可以随意忽略“ volatile”。
单个CPU处理单元和GPU单个处理单元有什么区别?
我在互联网上出现的大多数地方都涵盖了两者之间的高层差异.我想知道每个指令可以执行什么,它们的速度有多快以及这些处理单元如何集成到竞争架构中?
这似乎是一个答案很长的问题.所以很多链接都很好.
编辑:
在CPU中,FPU运行实数操作.在每个GPU核心中执行相同操作的速度有多快?如果快,那为什么它快?
我知道我的问题非常通用,但我的目标是回答这些问题.
我已经了解了不同的缓存映射技术,如直接映射,关联映射和集合关联映射技术,还学习了权衡.但我很好奇现在在intel core i7或AMD处理器中使用了什么.以及这些技术是如何演变的.还有哪些事情需要改进?
超线程技术是英特尔推出的一种同步多线程技术.
这些资源包括执行引擎,缓存和系统总线接口; 资源共享允许两个逻辑处理器更有效地相互协作,并允许停滞的逻辑处理器从另一个逻辑处理器借用资源.
在具有超线程的Intel CPU中,一个CPU内核(具有多个ALU)可以在同一时钟执行来自2个线程的指令.两个线程共享:存储缓冲区,缓存L1/L2和系统总线.
但是如果两个线程在一个Core上同时执行,则thread-1存储原子值,而thread-2加载此值,将用于此交换的内容:共享存储缓冲区,共享缓存L1/L2还是通常的缓存L3?
如果两个线程来自同一个进程(相同的虚拟地址空间)和两个不同进程(不同的虚拟地址空间),会发生什么?
Sandy Bridge Intel CPU - 缓存L1:
低12位 - 对于确定当前设定数值很重要
4 KB - 标准页面大小