Tad*_*zys 2 c++ linux multithreading gcc atomic
我对此感到困惑:在生产中,我们有两个进程通过共享内存进行通信,数据交换的一部分是漫长的,而且是一个bool.对此数据的访问不同步.它已经很好地工作了很长时间,现在仍然如此.我知道修改一个值不是原子的,但考虑到这些值被修改/访问了数百万次,这不得不失败?
这是一段代码示例,它在两个线程之间交换一个数字:
#include <pthread.h>
#include <xmmintrin.h>
typedef unsigned long long uint64;
const uint64 ITERATIONS = 500LL * 1000LL * 1000LL;
//volatile uint64 s1 = 0;
//volatile uint64 s2 = 0;
uint64 s1 = 0;
uint64 s2 = 0;
void* run(void*)
{
register uint64 value = s2;
while (true)
{
while (value == s1)
{
_mm_pause();// busy spin
}
//value = __sync_add_and_fetch(&s2, 1);
value = ++s2;
}
}
int main (int argc, char *argv[])
{
pthread_t threads[1];
pthread_create(&threads[0], NULL, run, NULL);
register uint64 value = s1;
while (s1 < ITERATIONS)
{
while (s2 != value)
{
_mm_pause();// busy spin
}
//value = __sync_add_and_fetch(&s1, 1);
value = ++s1;
}
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,我已经评论了几件事情:
// volatile uint64 s1 = 0;
和
// value = __sync_add_and_fetch(&s1,1);
__sync_add_and_fetch以原子方式递增变量.
我知道这不是很科学,但运行几次没有同步功能它完全没问题.此外,如果我测量两个版本的同步和没有同步,它们以相同的速度运行,为什么__sync_add_and_fetch没有添加任何开销?
我的猜测是编译器保证了这些操作的原子性,因此我没有看到生产中的问题.但仍无法解释为什么__sync_add_and_fetch不会增加任何开销(甚至在调试中运行).
关于矿山环境的更多细节:ubuntu 10.04,gcc4.4.3 intel i5 multicore cpu.
生产环境类似于它在更强大的CPU和Centos OS上运行.
谢谢你的帮助
基本上你在问"为什么我之间的行为/表现没有区别
s2++;
Run Code Online (Sandbox Code Playgroud)
和
__sync_add_and_fetch(&s2, 1);
Run Code Online (Sandbox Code Playgroud)
好吧,如果你去看看这两种情况下编译器生成的实际代码,你会发现存在差异 - s2++版本将有一个简单的INC指令(或者可能是一个ADD),而__sync版本将有该指令的LOCK前缀.
那么为什么没有LOCK前缀呢?好吧,虽然通常情况下需要LOCK前缀才能在任何基于x86的系统上运行,但事实证明它不需要它.使用基于Intel Core的芯片,LOCK仅需要通过总线在不同CPU之间进行同步.在单个CPU(即使有多个内核)上运行时,它会在没有它的情况下进行内部同步.
那你为什么看不到__sync案件的减速呢?嗯,Core i7是一个"有限"的芯片,因为它只支持单插槽系统,所以你不能拥有多个CPU.这意味着永远不需要LOCK,事实上CPU完全忽略了它.现在代码大1个字节,这意味着如果ifetch或decode有限,它会产生影响,但你不是,所以你看不出任何区别.
如果您要在多插槽Xeon系统上运行,您会看到LOCK前缀的(小)减速,并且还可以在非LOCK版本中看到(罕见)故障.