如果有两个线程访问全局变量,那么许多教程都说使变量volatile变为阻止编译器将变量缓存在寄存器中,从而无法正确更新.但是,访问共享变量的两个线程是通过互斥锁来调用保护的东西不是吗?但是在这种情况下,在线程锁定和释放互斥锁之间,代码处于一个关键部分,只有那个线程可以访问变量,在这种情况下变量不需要是volatile?
那么多线程程序中volatile的用途/目的是什么?
假设我们正在尝试使用tsc进行性能监控,我们希望防止指令重新排序.
这些是我们的选择:
1: rdtscp是序列化调用.它可以防止对rdtscp的调用进行重新排序.
__asm__ __volatile__("rdtscp; " // serializing read of tsc
"shl $32,%%rdx; " // shift higher 32 bits stored in rdx up
"or %%rdx,%%rax" // and or onto rax
: "=a"(tsc) // output to tsc variable
:
: "%rcx", "%rdx"); // rcx and rdx are clobbered
Run Code Online (Sandbox Code Playgroud)
但是,rdtscp仅适用于较新的CPU.所以在这种情况下我们必须使用rdtsc.但是rdtsc非序列化,因此单独使用它不会阻止CPU重新排序.
所以我们可以使用这两个选项中的任何一个来防止重新排序:
2:这是一个电话cpuid然后rdtsc.cpuid是一个序列化的电话.
volatile int dont_remove __attribute__((unused)); // volatile to stop optimizing
unsigned tmp;
__cpuid(0, tmp, tmp, tmp, …Run Code Online (Sandbox Code Playgroud) Linux内核lock; addl $0,0(%%esp)用作写屏障,而RE2库xchgl (%0),%0用作写屏障.有什么区别,哪个更好?
x86还需要读屏障指令吗?RE2将其读屏障功能定义为x86上的无操作,而Linux lfence根据SSE2是否可用将其定义为无操作或无操作.什么时候lfence需要?
据我所知,mfence硬件内存屏障asm volatile ("" : : : "memory")是一个编译器障碍.但是,可以asm volatile ("" : : : "memory")用来代替mfence.
我迷惑的原因是这个链接
我试图准确理解什么是内存障碍.根据我目前所知,存储器屏障(例如:) mfence用于防止指令从存储器屏障之前到之后和之后重新排序.
这是使用中的内存屏障的示例:
instruction 1
instruction 2
instruction 3
mfence
instruction 4
instruction 5
instruction 6
Run Code Online (Sandbox Code Playgroud)
现在我的问题是:mfence指令只是一个标记,告诉CPU执行指令的顺序是什么?或者它是CPU实际执行的指令,就像它执行其他指令(例如:) mov.
英特尔内存模型保证:
http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/
我已经看到声称由于Intel内存模型,SFENCE在x86-64上是多余的,但从来没有LFENCE.上述内存模型规则是否使指令冗余?
我阅读了"英特尔架构的英特尔优化指南指南".
但是,我仍然不知道何时应该使用
_mm_sfence()
_mm_lfence()
_mm_mfence()
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释在编写多线程代码时何时应该使用它们?
我正在玩这个答案的代码,稍微修改一下:
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序列和d的imul edx, edx一个): …
我一直在阅读关于superscalr和OoO的一些材料,我很困惑.
我认为他们的架构图看起来非常相似.
x86 ×7
assembly ×5
c++ ×4
atomic ×3
c ×2
concurrency ×2
performance ×2
cpu ×1
gcc ×1
intrinsics ×1
optimization ×1
perf ×1
rdtsc ×1
volatile ×1