相关疑难解决方法(0)

什么时候使用volatile多线程?

如果有两个线程访问全局变量,那么许多教程都说使变量volatile变为阻止编译器将变量缓存在寄存器中,从而无法正确更新.但是,访问共享变量的两个线程是通过互斥锁来调用保护的东西不是吗?但是在这种情况下,在线程锁定和释放互斥锁之间,代码处于一个关键部分,只有那个线程可以访问变量,在这种情况下变量不需要是volatile?

那么多线程程序中volatile的用途/目的是什么?

c++ concurrency multithreading atomic volatile

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

英特尔内存模型是否使SFENCE和LFENCE冗余?

英特尔内存模型保证:

  • 商店不会与其他商店重新订购
  • 载荷不会与其他载荷重新订购

http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/

我已经看到声称由于Intel内存模型,SFENCE在x86-64上是多余的,但从来没有LFENCE.上述内存模型规则是否使指令冗余?

optimization x86 assembly atomic memory-barriers

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

我什么时候应该使用_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
查看次数

了解lfence对具有两个长依赖链的循环的影响,以增加长度

我正在玩这个答案的代码,稍微修改一下:

BITS 64

GLOBAL _start

SECTION .text

_start:
 mov ecx, 1000000

.loop:

 ;T is a symbol defined with the CLI (-DT=...)

 TIMES T imul eax, eax
 lfence
 TIMES T imul edx, edx


 dec ecx
jnz .loop

 mov eax, 60           ;sys_exit
 xor edi, edi
 syscall
Run Code Online (Sandbox Code Playgroud)

没有lfence我,我得到的结果与答案中的静态分析一致.

当我介绍一个单一 lfence我期望的CPU执行imul edx, edx的序列的第k个平行于迭代imul eax, eax的下一个(的序列K + 1个)迭代.
像这样的东西(调用一个imul eax, eax序列和dimul edx, edx一个): …

performance x86 assembly cpu-architecture perf

13
推荐指数
2
解决办法
472
查看次数

lock xchg与mfence具有相同的行为吗?

我想知道的是lock xchg,mfence从一个线程访问内存位置的角度来看是否会有类似的行为,这个内存位置正在被其他线程进行变异(让我们随便说).它能保证我获得最新的价值吗?之后的内存读/写指令?

我混淆的原因是:

8.2.2"读取或写入不能通过I/O指令,锁定指令或序列化指令重新排序."

-Intel 64 Developers Manual Vol.3

这是否适用于线程?

mfence 状态:

对MFENCE指令之前发出的所有内存加载和存储到内存指令执行序列化操作.此序列化操作保证在MFENCE指令之前的任何加载或存储指令全局可见之前,在程序顺序之前的每条加载和存储指令都是全局可见的.MFENCE指令针对所有加载和存储指令,其他MFENCE指令,任何SFENCE和LFENCE指令以及任何序列化指令(例如CPUID指令)进行排序.

-Intel 64 Developers Manual Vol 3A

听起来更有力.因为它听起来mfence几乎正在刷写写缓冲区,或者至少延伸到写缓冲区和其他内核以确保我未来的加载/存储是最新的.

当基准标记时,两个指令都需要约100个循环才能完成.所以我无论如何都看不出那么大的差异.

主要是我只是困惑.我的指令基于lock互斥体使用,但后来这些包含没有内存栅栏.然后,我看到锁免费使用内存栅栏编程,但没有锁.我知道AMD64有一个非常强大的内存模型,但过时的值可以在缓存中持续存在.如果lock行为与行为不同,mfence那么互斥量如何帮助您查看最新值?

x86 assembly multithreading cpu-architecture memory-barriers

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

C++ 如何仅使用 MOV 在 x86 上实现释放和获取?

这个问题是对此的跟进/澄清:

MOV x86 指令是否实现了 C++11 memory_order_release 原子存储?

这表明MOV汇编指令足以在 x86 上执行获取-释放语义。我们不需要LOCK,围栏xchg等。但是,我很难理解这是如何工作的。

英特尔文档第 3A 卷第 8 章指出:

https://software.intel.com/sites/default/files/managed/7c/f1/253668-sdm-vol-3a.pdf

在单处理器(核心)系统中......

  • 读取不会与其他读取重新排序。
  • 写入不会与较旧的读取重新排序。
  • 对内存的写入不会与其他写入重新排序,但以下情况除外:

但这是针对单核的。多核部分似乎没有提到如何强制执行负载:

在多处理器系统中,以下排序原则适用:

  • 单个处理器使用与单处理器系统相同的排序原则。
  • 所有处理器都以相同的顺序观察单个处理器的写入。
  • 来自单个处理器的写入与来自其他处理器的写入无关。
  • 记忆排序服从因果关系(记忆排序尊重传递可见性)。
  • 除了执行存储的处理器之外的处理器以一致的顺序看到任何两个存储
  • 锁定指令具有总顺序。

那么如何才能MOV单独促进获取释放呢?

c++ x86 memory-model memory-barriers stdatomic

8
推荐指数
2
解决办法
800
查看次数

加载和存储是否只有重新排序的指令?

我已经阅读了很多关于内存排序的文章,并且所有这些文章都只说CPU重新加载和存储.

CPU(我对x86 CPU特别感兴趣)是否仅重新排序加载和存储,并且不重新排序它具有的其余指令?

x86 cpu-architecture memory-barriers

6
推荐指数
2
解决办法
915
查看次数

如何通过按顺序提交load-> store重新排序?

ARM允许重新排序加载后续存储,以便以下伪代码:

// CPU 0 | // CPU 1 temp0 = x; | temp1 = y; y = 1; | x = 1;

可以导致temp0 == temp1 == 1(并且,这在实践中也是可观察到的).我无法理解这是怎么发生的; 似乎有序提交会阻止它(这是我的理解,它存在于几乎所有的OOO处理器中).我的理由是"在提交之前,负载必须具有其值,它在存储之前提交,并且在提交之前,存储的值不会对其他处理器可见."

我猜我的一个假设肯定是错的,并且必须遵循下列之一:

  • 说明不需要提交一路有序.稍后的存储可以安全地提交并在之前的加载之前变得可见,只要在存储提交核心时可以保证先前的加载(以及所有中间指令)不会触发异常,并且加载的地址是保证与商店不同.

  • 负载可以在其值已知之前提交.我不知道如何实现这一点.

  • 商店在提交之前可以显示.也许某个内存缓冲区允许将存储转发到另一个线程的加载,即使负载先前已加入?

  • 还有别的吗?

有许多假设的微体系结构特征可以解释这种行为,但我最好的是那些实际存在于现代弱有序CPU中的那些.

arm cpu-architecture memory-barriers

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

Go 中的原子操作是否确保其他变量对其他线程可见?

这让我很困惑,我正在阅读 golang 内存模型,https://golang.org/ref/mem

var l sync.Mutex
var a string

func f() {
    a = "hello, world"
    l.Unlock()
}

func main() {
    l.Lock()
    go f()
    l.Lock()
    print(a)
}
Run Code Online (Sandbox Code Playgroud)

互斥锁通过原子解锁

UnLock: new := atomic.AddInt32(&m.state, -mutexLocked)

Lock: atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) 
Run Code Online (Sandbox Code Playgroud)

我的问题是,原子 AddInt32、CompareAndSwapInt32 是否会导致内存障碍,如果a在不同的 goroutine 中可见的话。

在java中,我知道AtomicInteger,内存屏障通过“易失性”,保持线程字段可见。

memory-model go memory-barriers

5
推荐指数
2
解决办法
1944
查看次数

x86 TSO 内存模型上的“存储缓冲区”试金石测试名称的原因

我一直在研究内存模型并看到了这个(引用自https://research.swtch.com/hwmm):

Litmus Test: Write Queue (also called Store Buffer)
Can this program see r1 = 0, r2 = 0?
// Thread 1           // Thread 2
x = 1                 y = 1
r1 = y                r2 = x
On sequentially consistent hardware: no.
On x86 (or other TSO): yes!

Run Code Online (Sandbox Code Playgroud)
  • 事实1:这是很多文章中提到的存储缓冲区试金石。他们都说,由于存储缓冲区的存在,TSO 上可能会发生 r1 和 r2 为零的情况。他们似乎假设所有存储和加载都按顺序执行,但结果是 r1 和 r2 都为零。后来得出的结论是“存储/加载重新排序可能会发生”,作为“存储缓冲区存在的后果”。

  • 事实 2:但是我们知道 OoO 执行也可以重新排序两个线程中的存储和加载。从这个意义上说,无论存储缓冲区如何,只要所有四个指令都在没有看到彼此对 x 或 y 无效的情况下退出,这种重新排序就可能导致 r1 和 r2 都为零。在我看来,“存储/加载重新排序可能会发生”,只是因为“它们是无序执行的”。(我对此可能是非常错误的,因为这是我所知道的最好的猜测和 OoO 执行。)

我想知道这两个事实是如何融合的(假设我碰巧对这两个事实都是正确的):存储缓冲区或 OoO 执行是“存储/加载重新排序”的原因,还是两者都是?

换句话说:假设我以某种方式在 x86 机器上观察到了这个试金石,是因为存储缓冲区还是 …

x86 cpu-architecture memory-model memory-barriers

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

内存屏障的传递性/累积性如何通过微体系结构实现?

我一直在阅读有关x86内存模型如何工作以及屏障指令在x86上的意义,并与其他体系结构(例如ARMv8)进行比较。在x86和ARMv8架构中,内存模型都遵循(无双关),即传递性/累积性,即如果CPU 1看到CPU0的存储,而CPU2看到CPU1的存储,则只有在CPU1看到CPU0的存储时才会发生,然后CPU2还必须查看CPU0的存储。我指的示例是保罗·麦肯尼(Paul McKenney)著名论文6.1节中的示例1和2(尽管相关,但他最新的性能手册《http://www.puppetmastertrading.com/images/hwViewForSwHackers》中也存在同样的问题。 pdf格式)。如果我理解正确,那么x86使用商店队列(或商店订单缓冲区)对商店进行排序(以及其他微体系结构优化),然后使其成为全局可见(即写入L1D)。我的问题是x86拱(和其他拱)如何实现(微架构)传递性?存储队列确保按特定顺序使特定CPU的存储在全局范围内可见,但是又如何确保一个CPU进行的存储排序与其他CPU进行的存储排序呢?

x86 x86-64 cpu-architecture memory-barriers micro-architecture

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

x86 CPU有多少个内存屏障指令?

我已经发现,在x86 CPU有以下内存屏障指令:mfencelfence,和sfence

x86 CPU是否仅具有这三个内存屏障指令,或者还有更多指令?

x86 assembly multithreading memory-barriers

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

Intel X86如何实现全店排序

由于其 TSO 内存模型,X86 保证所有商店的总顺序。我的问题是是否有人知道这是如何实际实施的。

我对所有 4 个围栏是如何实现的印象很好,所以我可以解释如何保留本地秩序。但是 4 个栅栏只会给 PO;它不会给您 TSO(我知道 TSO 允许旧商店跳到新负载前面,因此只需要 4 个围栏中的 3 个)。

单个地址上所有内存操作的总顺序是一致性的责任。但我想知道英特尔(特别是 Skylake)如何在多个地址的商店上实现总订单。

x86 intel cpu-architecture memory-barriers micro-architecture

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