__asm易失的是什么("pause" ::::"memory");做? [英] What does __asm volatile ("pause" ::: "memory"); do?
问题描述
我正在研究一个具有以下代码结构的开源C ++项目:
I am looking at an open source C++ project which has the following code structure:
while(true) {
// Do something work
if(some_condition_becomes_true)
break;
__asm volatile ("pause" ::: "memory");
}
最后一条语句的作用是什么?我了解__asm
意味着这是一条汇编指令,并且我发现了一些有关pause
指令的帖子,这些帖子说该线程有效地暗示了内核释放资源并为其他线程提供了更多资源(在超线程的情况下).但是:::
做什么,memory
做什么?
What does the last statement do? I understand that __asm
means that it is an assembly instruction and I found some posts about pause
instruction which say that the thread effectively hints the core to release resources and give other thread more resources (in context of hyper-threading). But what does :::
do and what does memory
do?
推荐答案
它是_mm_pause()
和一个封装在一个GNU C扩展ASM语句中的编译内存屏障. https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
It's _mm_pause()
and a compile memory barrier wrapped into one GNU C Extended ASM statement. https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
asm("" ::: "memory")
防止对它的内存操作进行编译时重新排序,例如C ++ 11 std::atomic_signal_fence(std::memory_order_seq_cst)
. (不是 atomic_thread_fence
;尽管在x86上,防止编译时重新排序足以使它成为获取+释放栅栏,因为x86允许的唯一运行时重新排序是StoreLoad.)请参阅Jeff Preshing的在编译时进行内存排序文章.
asm("" ::: "memory")
prevents compile-time reordering of memory operations across it, like C++11 std::atomic_signal_fence(std::memory_order_seq_cst)
. (not atomic_thread_fence
; although on x86 preventing compile-time reordering is sufficient to make it an acquire + release fence because the only run-time reordering that x86 allows is StoreLoad.) See Jeff Preshing's Memory Ordering at Compile Time article.
将asm指令部分设为非空也意味着,每次C逻辑运行该源代码行时,这些asm指令都将运行(因为它是volatile
).
Making the asm instruction part non-empty also means those asm instructions will run every time the C logically runs that source line (because it's volatile
).
pause
防止推测性负载导致内存顺序错误的推测管道清除(也称为机器核).在等待看到内存中值的自旋循环中,这很有用.
pause
prevents speculative loads from causing memory-ordering mis-speculation pipeling clears (aka machine nukes). It's useful inside spin loops that are waiting to see a value in memory.
您可能会在不使用C ++ 11 std :: atomic编写的spinloop内找到此语句,以告诉编译器必须重新读取全局变量的值. (因为"memory"
破坏符意味着编译器必须假定asm语句可能已修改了任何全局可访问的内存的值.)
You might find this statement inside a spinloop written without C++11 std::atomic, to tell the compiler it has to re-read the value of a global variable. (Because the "memory"
clobber means the compiler has to assume the asm statement might have modified the value of any globally-reachable memory.)
这看起来像是您在其中找到它的上下文:some_condition_becomes_true
可能包括读取非atomic
/非volatile
全局变量.
This looks like the context where you found it: some_condition_becomes_true
probably includes reading a non-atomic
/ non-volatile
global.
相当于您的循环的C ++ 11:
The C++11 equivalent of your loop:
#include <atomic>
#include <immintrin.h>
std::atomic<int> flag;
void wait_for_flag(void) {
while(flag.load(std::memory_order_seq_cst == 0) {
_mm_pause();
}
}
(不完全等效,因为您的版本具有完整的编译器障碍,而我的版本仅具有seq-cst负载,因此它不是完整的信号范围.但是可能是不需要的,他们只是使用了比必要的更强的东西来获得挥发的效果.
(Not exactly equivalent, because your version has a full compiler barrier while mine only has a seq-cst load, so it's not a full signal-fence. But probably what wasn't needed, and they just used something stronger than necessary to get the effect of volatile).
没有障碍或没有成为flag
原子,编译器会对其进行优化以实现:
Without the barrier or making flag
atomic, the compiler would have optimized it to:
// Do something work
if(some_condition_becomes_true) {
// empty
} else {
while(true) {
// Do something work
__asm volatile ("pause" ::: ); // no memory clobber
}
}
即它将使对some_condition_becomes_true
的检查脱离循环,并且不每次都重新读取全局.
i.e. it would hoist the check on some_condition_becomes_true
out of the loop and not re-read the global every time.
这篇关于__asm易失的是什么("pause" ::::"memory");做?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!