我__sync_fetch_and_add使用自己的atomic模板已经使用gcc的Intel兼容内置(如)了很长一段时间." __sync"功能现在被正式视为"遗产".
C++ 11支持std::atomic<>及其后代,因此使用它似乎是合理的,因为它使我的代码符合标准,并且编译器将以平台无关的方式生成最佳代码,这几乎太好了真正.
顺便说一下,我也只需atomic要用文字替换std::atomic.有很多的std::atomic(重:内存模型),我真的不需要,但默认参数采取照顾.
现在是坏消息.事实证明,从我所知道的,生成的代码是......彻底的废话,甚至根本不是原子的.即使是增加一个单个原子变量并把它输出具有不少于5个非内联函数调用的最小例子___atomic_flag_for_address,___atomic_flag_wait_explicit和__atomic_flag_clear_explicit(完全优化),并且在另一方面,没有在所生成的可执行的单个原子指令.
是什么赋予了?当然总是存在编译器错误的可能性,但是对于大量的审阅者和用户来说,这种相当激烈的事情通常不会被忽视.这意味着,这可能不是一个错误,而是预期的行为.
这么多函数调用背后的"基本原理"是什么,以及如何在没有原子性的情况下实现原子性?
尽可能简单的例子:
#include <atomic>
int main()
{
std::atomic_int a(5);
++a;
__builtin_printf("%d", (int)a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
产生以下内容.s:
movl $5, 28(%esp) #, a._M_i
movl %eax, (%esp) # tmp64,
call ___atomic_flag_for_address #
movl $5, 4(%esp) #,
movl %eax, %ebx #, __g
movl %eax, (%esp) # __g,
call ___atomic_flag_wait_explicit #
movl %ebx, (%esp) # __g,
addl $1, 28(%esp) #, MEM[(__i_type *)&a]
movl $5, 4(%esp) #,
call _atomic_flag_clear_explicit #
movl %ebx, (%esp) # __g,
movl $5, 4(%esp) #,
call ___atomic_flag_wait_explicit #
movl 28(%esp), %esi # MEM[(const __i_type *)&a], __r
movl %ebx, (%esp) # __g,
movl $5, 4(%esp) #,
call _atomic_flag_clear_explicit #
movl $LC0, (%esp) #,
movl %esi, 4(%esp) # __r,
call _printf #
(...)
.def ___atomic_flag_for_address; .scl 2; .type 32; .endef
.def ___atomic_flag_wait_explicit; .scl 2; .type 32; .endef
.def _atomic_flag_clear_explicit; .scl 2; .type 32; .endef
Run Code Online (Sandbox Code Playgroud)
......并且所提到的功能看起来像这样objdump:
004013c4 <__atomic_flag_for_address>:
mov 0x4(%esp),%edx
mov %edx,%ecx
shr $0x2,%ecx
mov %edx,%eax
shl $0x4,%eax
add %ecx,%eax
add %edx,%eax
mov %eax,%ecx
shr $0x7,%ecx
mov %eax,%edx
shl $0x5,%edx
add %ecx,%edx
add %edx,%eax
mov %eax,%edx
shr $0x11,%edx
add %edx,%eax
and $0xf,%eax
add $0x405020,%eax
ret
Run Code Online (Sandbox Code Playgroud)
其他的稍微简单,但我找不到一个真正原子的指令(除了一些在X86 xchg上是原子的假,但这些似乎是NOP/padding,因为它正在xchg %ax,%ax跟随ret).
我完全不确定需要这样一个相当复杂的功能,以及它是如何制造任何原子的.
chi*_*ill 14
这是一个不合适的编译器构建.
检查你的c++config.h,它看起来像这样,但它没有:
/* Define if builtin atomic operations for bool are supported on this host. */
#define _GLIBCXX_ATOMIC_BUILTINS_1 1
/* Define if builtin atomic operations for short are supported on this host.
*/
#define _GLIBCXX_ATOMIC_BUILTINS_2 1
/* Define if builtin atomic operations for int are supported on this host. */
#define _GLIBCXX_ATOMIC_BUILTINS_4 1
/* Define if builtin atomic operations for long long are supported on this
host. */
#define _GLIBCXX_ATOMIC_BUILTINS_8 1
Run Code Online (Sandbox Code Playgroud)
根据configure测试定义或不定义这些宏,测试检查主机对__sync_XXX功能的支持.这些测试都在libstdc++v3/acinclude.m4,AC_DEFUN([GLIBCXX_ENABLE_ATOMIC_BUILTINS] ....
在您的安装中,从MEM[(__i_type *)&a]汇编文件中的放置显而易见-fverbose-asm,编译器使用宏atomic_0.h,例如:
#define _ATOMIC_LOAD_(__a, __x) \
({typedef __typeof__(_ATOMIC_MEMBER_) __i_type; \
__i_type* __p = &_ATOMIC_MEMBER_; \
__atomic_flag_base* __g = __atomic_flag_for_address(__p); \
__atomic_flag_wait_explicit(__g, __x); \
__i_type __r = *__p; \
atomic_flag_clear_explicit(__g, __x); \
__r; })
Run Code Online (Sandbox Code Playgroud)
使用正确构建的编译器,使用示例程序,c++ -m32 -std=c++0x -S -O2 -march=core2 -fverbose-asm应该生成如下内容:
movl $5, 28(%esp) #, a.D.5442._M_i
lock addl $1, 28(%esp) #,
mfence
movl 28(%esp), %eax # MEM[(const struct __atomic_base *)&a].D.5442._M_i, __ret
mfence
movl $.LC0, (%esp) #,
movl %eax, 4(%esp) # __ret,
call printf #
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3007 次 |
| 最近记录: |