Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我可以在多核x86 CPU上强制缓存一致性吗?_C++_Multithreading_X86_Multicore_Cpu Cache - Fatal编程技术网

C++ 我可以在多核x86 CPU上强制缓存一致性吗?

C++ 我可以在多核x86 CPU上强制缓存一致性吗?,c++,multithreading,x86,multicore,cpu-cache,C++,Multithreading,X86,Multicore,Cpu Cache,前几周,我编写了一个小线程类和一个单向消息管道,以允许线程之间的通信(显然,每个线程两个管道用于双向通信)。在我的Athlon 64 X2上一切正常,但我想知道如果两个线程都在查看同一个变量,并且每个核心上该变量的本地缓存值不同步,我是否会遇到任何问题 我知道volatile关键字会强制一个变量从内存刷新,但是在多核x86处理器上有没有办法强制所有内核的缓存同步?这是我需要担心的问题吗?还是volatile和轻量级锁定机制的正确使用(我使用_InterlockedExchange设置volati

前几周,我编写了一个小线程类和一个单向消息管道,以允许线程之间的通信(显然,每个线程两个管道用于双向通信)。在我的Athlon 64 X2上一切正常,但我想知道如果两个线程都在查看同一个变量,并且每个核心上该变量的本地缓存值不同步,我是否会遇到任何问题

我知道volatile关键字会强制一个变量从内存刷新,但是在多核x86处理器上有没有办法强制所有内核的缓存同步?这是我需要担心的问题吗?还是volatile和轻量级锁定机制的正确使用(我使用_InterlockedExchange设置volatile管道变量)能够处理我想要为多核x86 CPU编写“无锁”代码的所有情况


我已经知道并使用了关键部分、互斥体、事件等。我最想知道的是,是否有x86内部函数我不知道可以使用哪种强制或强制执行缓存一致性。

Volatile无法做到这一点。在C++中,易失性只会影响编译器优化,例如在登记器中存储变量而不是内存,或者完全删除它。

< P>不必担心缓存一致性。硬件会处理好的。您可能需要担心的是缓存一致性导致的性能问题

如果core#1写入变量,则会使其他core中缓存线的所有其他副本无效(因为它必须在提交存储之前获取缓存线的副本)。当core#2读取相同的变量时,它将在缓存中丢失(除非core#1已经将其写回共享级别的缓存)

由于整个缓存线(64字节)必须从内存中读取(或写回共享缓存,然后由core#2读取),因此会有一些性能成本。在这种情况下,这是不可避免的。这是理想的行为


问题是,当同一缓存线中有多个变量时,处理器可能会花费额外的时间保持缓存同步,即使核心在同一缓存线中读取/写入不同的变量


通过确保这些变量不在同一缓存线中,可以避免这种开销。这种效果称为假共享,因为您强制处理器同步线程之间未实际共享的对象的值。

您没有指定正在使用的编译器,但如果您在windows上,请查看。还可以看看可用的s。您可能需要注意的是,一般来说,
volatile
不足以完成您希望它完成的任务,但在VC 2005和2008下,添加了一些非标准语义,在读写操作周围添加了隐含的内存障碍


如果你想让事情变得可移植,你将面临一条更加艰难的道路。

volatile
只会迫使你的代码重新读取值,它无法控制从何处读取值。如果代码最近读取了该值,则该值可能位于缓存中,在这种情况下,volatile将强制从缓存而不是内存中重新读取该值

x86中没有太多缓存一致性指令。有预取指令,如,但这并不影响内存排序语义。它过去是通过在不污染二级缓存的情况下将值引入一级缓存来实现的,但对于具有大型共享包容性三级缓存的现代英特尔设计来说,情况更为复杂

x86 CPU使用一种变体(MESIF用于Intel,MOESI用于AMD)来保持它们的缓存彼此一致(包括不同内核的专用L1缓存)。要写入缓存线的内核必须强制其他内核使其副本失效,然后才能将其自身副本从共享状态更改为修改状态


在x86上,在一个线程中生成数据并在另一个线程中使用数据不需要任何fence指令(如MFENCE),因为x86加载/存储具有内置功能。您确实需要MFENCE(完全屏障)来获得顺序一致性。(此答案的前一版本建议需要
clflush
,这是不正确的)


您确实需要防止,因为C++的内存模型是弱有序的
volatile
是一种古老而糟糕的方法;C++11 std::atomic是编写无锁代码的一种更好的方法。

Herb Sutter似乎认为任何两个变量都应该驻留在单独的缓存线上。他在并发队列中执行此操作,并在锁和节点指针之间填充


编辑:如果您使用的是英特尔编译器或GCC,则可以使用,这似乎尽了最大努力在可能的情况下抢占缓存。

由于x86处理器采用的MESI协议,内核之间的缓存一致性得到了保证。在处理外部硬件时,您只需担心内存一致性,因为外部硬件可能会在数据仍位于内核缓存上时访问内存。不过,这里的情况与您的情况不同,因为文本表明您正在使用userland进行编程。

有一系列文章介绍了现代内存体系结构,包括和更多现代体系结构主题


文章可读性很强,插图也很好。享受吧

您的问题中有几个子问题,因此我将尽我所知回答它们

目前,在C++中没有实现无锁交互的可移植方式。C++0x方案通过引入原子库解决了这一问题
  • Volatile不能保证在多核上提供原子性,其实现是特定于供应商的
  • 在x86上,除了将共享变量声明为volatile以防止一些可能破坏多线程代码的编译器优化之外,您不需要做任何特殊的事情。Volatile告诉编译器不要缓存值
  • 有些算法(例如Dekker)不起作用