Sun*_*nda 4 c++ thread-safety static-initialization c++11
我们知道局部静态变量初始化在 C++11 中是线程安全的,现代编译器完全支持这一点。(在 C++11 中局部静态变量初始化线程安全吗?)
使其线程安全的成本是多少?我知道这很可能依赖于编译器实现。
上下文:我有一个多线程应用程序(10 个线程)通过以下函数以非常高的速率访问单例对象池实例,我担心它的性能影响。
template <class T>
ObjectPool<T>* ObjectPool<T>::GetInst()
{
static ObjectPool<T> instance;
return &instance;
}
Run Code Online (Sandbox Code Playgroud)
查看生成的汇编代码会有所帮助。
#include <vector>
std::vector<int> &get(){
static std::vector<int> v;
return v;
}
int main(){
return get().size();
}
Run Code Online (Sandbox Code Playgroud)
std::vector<int, std::allocator<int> >::~vector():
movq (%rdi), %rdi
testq %rdi, %rdi
je .L1
jmp operator delete(void*)
.L1:
rep ret
get():
movzbl guard variable for get()::v(%rip), %eax
testb %al, %al
je .L15
movl get()::v, %eax
ret
.L15:
subq $8, %rsp
movl guard variable for get()::v, %edi
call __cxa_guard_acquire
testl %eax, %eax
je .L6
movl guard variable for get()::v, %edi
movq $0, get()::v(%rip)
movq $0, get()::v+8(%rip)
movq $0, get()::v+16(%rip)
call __cxa_guard_release
movl $__dso_handle, %edx
movl get()::v, %esi
movl std::vector<int, std::allocator<int> >::~vector(), %edi
call __cxa_atexit
.L6:
movl get()::v, %eax
addq $8, %rsp
ret
main:
subq $8, %rsp
call get()
movq 8(%rax), %rdx
subq (%rax), %rdx
addq $8, %rsp
movq %rdx, %rax
sarq $2, %rax
ret
Run Code Online (Sandbox Code Playgroud)
相比
#include <vector>
static std::vector<int> v;
std::vector<int> &get(){
return v;
}
int main(){
return get().size();
}
Run Code Online (Sandbox Code Playgroud)
std::vector<int, std::allocator<int> >::~vector():
movq (%rdi), %rdi
testq %rdi, %rdi
je .L1
jmp operator delete(void*)
.L1:
rep ret
get():
movl v, %eax
ret
main:
movq v+8(%rip), %rax
subq v(%rip), %rax
sarq $2, %rax
ret
movl $__dso_handle, %edx
movl v, %esi
movl std::vector<int, std::allocator<int> >::~vector(), %edi
movq $0, v(%rip)
movq $0, v+8(%rip)
movq $0, v+16(%rip)
jmp __cxa_atexit
Run Code Online (Sandbox Code Playgroud)
我对汇编程序不是很好,但我可以看到在第一个版本v中它周围有一个锁并且get没有内联,而在第二个版本get中基本上已经消失了。
你可以玩各种编译器和优化标志,但似乎没有编译器能够内联或优化了锁,即使该方案显然是单线程的。
您可以添加staticto getwhich 使 gcc 内联,get同时保留锁定。
要了解这些锁和额外指令对您的编译器、标志、平台和周围代码的成本,您需要进行适当的基准测试。
我希望锁有一些开销并且比内联代码慢得多,当您实际使用向量时,这变得无关紧要,但是如果不进行测量,您永远无法确定。
| 归档时间: |
|
| 查看次数: |
1505 次 |
| 最近记录: |