请考虑以下压缩代码:
/* Compile: gcc -pthread -m32 -ansi x.c */
#include <stdio.h>
#include <inttypes.h>
#include <pthread.h>
static volatile uint64_t v = 0;
void *func (void *x) {
__sync_add_and_fetch (&v, 1);
return x;
}
int main (void) {
pthread_t t;
pthread_create (&t, NULL, func, NULL);
pthread_join (t, NULL);
printf ("v = %"PRIu64"\n", v);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我有一个uint64_t我想以原子方式递增的变量,因为该变量是多线程程序中的计数器.为了实现原子性,我使用了GCC的原子内置.
如果我编译amd64系统(-m64),生成的汇编代码很容易理解.通过使用a lock addq,处理器保证增量是原子的.
400660: f0 48 83 05 d7 09 20 lock addq $0x1,0x2009d7(%rip)
Run Code Online (Sandbox Code Playgroud)
但是相同的C代码在ia32系统(-m32)上产生了非常复杂的ASM代码:
804855a: a1 28 a0 04 …Run Code Online (Sandbox Code Playgroud) 我正在使用一些原子变量,所有unsigned int,我想将它们收集到一个结构中 - 实际上是一个POD.但是我也想要一个构造函数,因为我的编译器不是c ++ 11(所以我必须定义自己的构造函数来创建初始值).
所以最初我有:
// Names are not the real names - this is just for example
std::atomic<int> counter1;
std::atomic<int> counter2;
std::atomic<int> counter3;
Run Code Online (Sandbox Code Playgroud)
然后我很乐意根据需要增加/减少它们.但后来我决定再多一些计数器,因此将它们放入一个结构中:
struct my_counters {
int counter1;
int counter2;
int counter3;
// Constructor so that I can init the values I want.
my_counters(c1, c2, c3) : counter1(c1), counter2(c2), counter3(c3){;}
};
Run Code Online (Sandbox Code Playgroud)
但是因为我添加了一个自定义构造函数,所以这在技术上不再是POD.我正在阅读有关此问题的其他问题,他们说使用std :: atomic我需要一个POD,但我读到的其他问题表明结构需要是可复制的或者一些这样的...无论如何,我感到很困惑,我想要要知道我是否可以安全地使用我的结构my_counters作为原子类型:
std::atomic<my_counters> counters;
Run Code Online (Sandbox Code Playgroud)
然后在各种线程内:
// Are these operations now still atomic (and therefore safe to use across threads):
counters.counter1++;
counters.counter2--;
counters.counter3 …Run Code Online (Sandbox Code Playgroud)