相关疑难解决方法(0)

在x86/x86_64处理器上使用LFENCE指令是否有意义?

通常在互联网上我发现LFENCE在处理器x86中没有任何意义,即它什么都不做,所以相反MFENCE我们可以绝对无痛地使用SFENCE,因为MFENCE= SFENCE+ LFENCE= SFENCE+ NOP= SFENCE.

但是如果LFENCE没有意义,那么为什么我们有四种方法在x86/x86_64中建立顺序一致性:

  1. LOAD(没有围栏)和STORE+MFENCE
  2. LOAD (没有围栏)和 LOCK XCHG
  3. MFENCE+ LOADSTORE(没有围栏)
  4. LOCK XADD(0)和STORE(没有围栏)

取自这里:http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

以及Herb Sutter在第34页底部的表演:https://skydrive.live.com/view.aspx?status = 4E86B0CF20EF15AD!24884&app = WordPdf&wdo = 2&authkey =!AMtj_EflYn2507c

如果LFENCE没有做任何事情,那么方法(3)将具有以下含义:SFENCE + LOAD and STORE (without fence)但是SFENCE之前没有任何意义LOAD.即如果LFENCE什么都不做,方法(3)没有意义.

LFENCE在处理器x86/x86_64中是否有任何意义上的指令?

回答:

1. …

x86 assembly x86-64 atomic memory-barriers

40
推荐指数
2
解决办法
1万
查看次数

为什么GCC不使用LOAD(没有fence)和STORE + SFENCE来实现顺序一致性?

以下是在x86/x86_64中实现顺序一致性的四种方法:

  1. 加载(没有围栏)和STORE + MFENCE
  2. 加载(没有围栏)和LOCK XCHG
  3. MFENCE + LOAD和STORE(没有栅栏)
  4. LOCK XADD(0)和STORE(没有围栏)

正如它在这里写的:http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

C/C++ 11操作x86实现

  • 加载Seq_Cst:MOV(来自内存)
  • Store Seq Cst:(LOCK)XCHG //替代方案:MOV(进入内存),MFENCE

注意:有一个C/C++ 11到x86的替代映射,而不是锁定(或屏蔽)Seq Cst存储锁/隔离Seq Cst加载:

  • 加载Seq_Cst:LOCK XADD(0)//替代:MFENCE,MOV(来自内存)
  • Store Seq Cst:MOV(进入内存)

GCC 4.8.2(x86_64中的GDB)对C++ 11-std :: memory_order_seq_cst使用第一种方法,即LOAD(没有fence)和STORE + MFENCE:

std::atomic<int> a;
int temp = 0;
a.store(temp, std::memory_order_seq_cst);
0x4613e8  <+0x0058>         mov    0x38(%rsp),%eax
0x4613ec  <+0x005c>         mov    %eax,0x20(%rsp)
0x4613f0  <+0x0060>         mfence
Run Code Online (Sandbox Code Playgroud)

我们知道,MFENCE = LFENCE + SFENCE.然后这段代码我们可以重写为:LOAD(without fence) and STORE+LFENCE+SFENCE

问题:

  1. 为什么我们不需要在LOAD之前使用LFENCE,并且需要在STORE之后使用LFENCE(因为LFENCE仅在LOAD之前才有意义!)?
  2. 为什么GCC不使用方法:对于std :: memory_order_seq_cst,LOAD(没有fence)和STORE + SFENCE?

c++ x86 multithreading gcc c++11

15
推荐指数
4
解决办法
2991
查看次数

我什么时候应该使用_mm_sfence _mm_lfence和_mm_mfence

我阅读了"英特尔架构的英特尔优化指南指南".

但是,我仍然不知道何时应该使用

_mm_sfence()
_mm_lfence()
_mm_mfence()
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释在编写多线程代码时何时应该使用它们?

c++ x86 multithreading intrinsics memory-barriers

14
推荐指数
3
解决办法
6488
查看次数

x86-SSE指令是否具有自动发布 - 获取订单?

正如我们从C11-memory_order所知道的那样:http://en.cppreference.com/w/c/atomic/memory_order

从C++ 11-std :: memory_order开始:http://en.cppreference.com/w/cpp/atomic/memory_order

在强排序系统(x86,SPARC,IBM大型机)上, 发布 - 获取顺序是自动的.没有为此同步模式发出额外的CPU指令,只会影响某些编译器优化(例如,禁止编译器在原子存储释放之前移动非原子存储或在原子载荷获取之前执行非原子加载)

但这对于x86-SSE指令是否正确(除了[NT] - 非时间,我们总是必须使用L/S/MFENCE)?

这里说,"sse指令......不要求向后兼容性,并且内存顺序未定义".据信,当需要时,严格的可订购性与旧版本的处理器x86兼容,但是新的命令,即SSE(除了[NT]) - 被剥夺了自动释放 - 获取订单,是吗?

x86 sse memory-barriers c++11 c11

8
推荐指数
1
解决办法
799
查看次数

`std :: memory_order_acquire`的语义是否需要x86/x86_64上的处理器指令?

众所周知,在x86上,操作load()store()内存屏障memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel不需要处理器指令用于缓存和管道,并且汇编程序的代码总是对应std::memory_order_relaxed,并且这些限制仅对编译器的优化是必需的:http:// www. stdthread.co.uk/forum/index.php?topic=72.0

此代码反汇编代码确认store()(MSVS2012 x86_64):

std::atomic<int> a;
    a.store(0, std::memory_order_relaxed);
000000013F931A0D  mov         dword ptr [a],0  
    a.store(1, std::memory_order_release);
000000013F931A15  mov         dword ptr [a],1  
Run Code Online (Sandbox Code Playgroud)

但是这段代码并没有为load()(MSVS2012 x86_64)确认这一点,使用lock cmpxchg:

    int val = a.load(std::memory_order_acquire);
000000013F931A1D  prefetchw   [a]  
000000013F931A22  mov         eax,dword ptr [a]  
000000013F931A26  mov         edx,eax  
000000013F931A28  lock cmpxchg dword ptr [a],edx  
000000013F931A2E  jne         main+36h (013F931A26h)  

    std::cout << val << "\n";
Run Code Online (Sandbox Code Playgroud)

安东尼威廉姆斯说 …

c++ concurrency x86 memory-barriers c++11

7
推荐指数
1
解决办法
1034
查看次数

x86上的两个后续CPU存储是否刷新到缓存保持顺序?

假设有两个线程分别在x86 CPU0和CPU1上运行.在CPU0上运行的线程执行以下命令:

A=1
B=1
Run Code Online (Sandbox Code Playgroud)

包含A的缓存行,最初由CPU1拥有,并且包含由CPU0拥有的B.

我有两个问题:

  1. 如果我理解正确,两个存储都将被放入CPU的存储缓冲区.但是,对于第一个存储A=1,CPU1的高速缓存必须无效,而第二个存储B=1可以立即刷新,因为CPU0拥有包含它的高速缓存行.我知道x86 CPU尊重商店订单.这是否意味着B=1以前不会写入缓存A=1

  2. 假设在CPU1中执行以下命令:

而(B = 0);
打印A.

是否足以加之间只有lfence whileprint命令在CPU1不添加之间的SFENCE A=1B=1在CPU0得到1总是在x86上打印出来?

while (B=0);
lfence
print A
Run Code Online (Sandbox Code Playgroud)

cpu x86 multithreading cpu-cache

6
推荐指数
1
解决办法
637
查看次数

为什么(或不是?)SFENCE + LFENCE相当于MFENCE?

正如我们从之前的回答中所知道的,它是否在处理器x86/x86_64中指示LFENCE?我们不能使用SFENCE而不是MFENCE顺序一致性.

这里的答案表明MFENCE= SFENCE+ LFENCE,即LFENCE没有我们不能提供顺序一致性的东西.

LFENCE 无法重新排序:

SFENCE
LFENCE
MOV reg, [addr]
Run Code Online (Sandbox Code Playgroud)

- 到 - >

MOV reg, [addr]
SFENCE
LFENCE
Run Code Online (Sandbox Code Playgroud)

例如重新排序MOV [addr], reg LFENCE- > LFENCE MOV [addr], reg机制提供- 存储缓冲区,它重新排序存储 - 负载以提高性能,并且因为LFENCE它不会阻止它.并SFENCE 禁用此机制.

什么机制禁用LFENCE无法重新排序(x86没有机制 - Invalidate-Queue)?

并且只是在理论上或者在现实中重新排序SFENCE MOV reg, [addr]- > MOV reg, [addr] SFENCE可能吗?如果可能,实际上,什么机制,它是如何工作的?

x86 assembly x86-64 memory-fences memory-barriers

5
推荐指数
3
解决办法
1091
查看次数

内存防护会阻止多核 CPU 中的线程吗?

我正在阅读英特尔指令集指南 64-ia-32指南 以了解内存栅栏。我的问题是,以 SFENCE 为例,为了确保所有存储操作都是全局可见的,多核 CPU 是否会停放所有线程甚至在其他内核上运行,直到实现缓存一致性?

x86 multithreading multicore cpu-architecture memory-barriers

5
推荐指数
1
解决办法
845
查看次数

x86 mfence和C ++内存屏障

我正在检查编译器如何为x86_64上的多核内存屏障发出指令。以下代码是我正在测试的代码gcc_x86_64_8.3

std::atomic<bool> flag {false};
int any_value {0};

void set()
{
  any_value = 10;
  flag.store(true, std::memory_order_release);
}

void get()
{
  while (!flag.load(std::memory_order_acquire));
  assert(any_value == 10);
}

int main()
{
  std::thread a {set};
  get();
  a.join();
}
Run Code Online (Sandbox Code Playgroud)

使用时std::memory_order_seq_cst,我可以看到该MFENCE指令用于任何优化-O1, -O2, -O3。该指令确保刷新了存储缓冲区,因此在L1D缓存中更新了它们的数据(并使用MESI协议确保其他线程可以看到效果)。

但是,当我std::memory_order_release/acquire不进行优化MFENCE使用时,也会使用指令,但是使用-O1, -O2, -O3优化会忽略该指令,并且不会看到其他刷新缓冲区的指令。

MFENCE不使用的情况下,如何确保将存储缓冲区数据提交给高速缓存以确保内存顺序语义?

以下是使用get / set函数的汇编代码-O3,例如我们在Godbolt编译器资源管理器中获得的代码

set():
        mov     DWORD PTR any_value[rip], 10
        mov     BYTE PTR flag[rip], 1
        ret


.LC0:
        .string …
Run Code Online (Sandbox Code Playgroud)

x86 gcc memory-model memory-barriers c++11

4
推荐指数
2
解决办法
470
查看次数

一个读者一个编写者,int或atomic_int

我知道这不是一个新问题,但在阅读了关于c ++ 11内存栅栏后我感到困惑;

如果我有一个读者线程和一个编写器线程.
我可以使用普通的int吗?

    int x = 0; // global
writer    reader
x = 1;    printf("%d\n", x);
Run Code Online (Sandbox Code Playgroud)

这种行为是不确定的?
我可以在读者线程中获得未定义的值吗?
或者就像使用std::atomic_uint_fast32_tstd::atomic<int>?因此,价值将会到达读者线程 - 最终.

    std::atomic<int x = 0; // global
writer                                    reader
x.store(1, std::memory_order_relaxed);    printf("%d\n", x.load(std::memory_order_relaxed));
Run Code Online (Sandbox Code Playgroud)

答案取决于我使用的平台吗?(例如x86),所以加载/存储普通int是一条CPU指令?

如果两种行为都相似,那么我是否应该期望两种类型的性能相同?

c++ multithreading atomic memory-fences c++11

1
推荐指数
1
解决办法
410
查看次数