是单核CPU上的变量写入原子?

时间:2016-08-09 00:18:30

标签: c++ multithreading atomic

我有一个带有两个线程的单核CPU(ARM Cortex M3,32位)。假设有以下情况:

// Thread 1:
int16_t a = 1;
double b = 1.0;
// Do some other fancy stuff including starting Thread 2
for (;;) {std::cout << a << "," <<b;}

// Thread 2:
a = 2;
b = 2.0;

我可以处理以下输出:

  • 1,1
  • 1,2
  • 2,1
  • 2,2

我可以确定输出总是其中一个(1/2)而不使用mutex或其他锁定机制吗?更具体地说,这个编译器是依赖的​​吗? int16double的行为是否有所不同?

2 个答案:

答案 0 :(得分:2)

这主要取决于CPU,但理论上,在C11之前涉及多个线程的任何内容都是最佳实现定义,最糟糕的是未定义的行为,因此编译器可能会做任何事情。

如果您可以忽略那些做傻事的疯狂编译器,并假设编译器将以合理的方式使用CPU的设施,那么它主要取决于CPU支持的内容。

Cortex-M3是一个32位CPU,具有32位总线,没有FPU。因此,32位和更小值的读取和写入通常是原子的。但是,double是64位,因此对double的任何读/写都将涉及两个指令并且是非原子的。因此,如果一个线程在另一个线程写入时读取,则可能从一个值获得一半而另一个值获得一半。

现在在您的具体示例中,值1.0和2.0的下半部分都是0,因此'mix'将是无害的,但其他值将不具有该行为。

答案 1 :(得分:1)

之前的操作评估顺序;不能保证从左到右,即使它是,它们不是原子的,如果你尝试同时读取和写入,你将得到一个段错误(它们可以&amp; do做多个周期来执行和上下文切换可以打断它。)

特别是在arm上,读取和写入在cpu中的队列中可以自由重新排序(除了过去的内存障碍),即使在没有重新排序内存的cpu上,编译器也可以自由地重新排序它们。没有什么可以阻止你的任务和读取前进或后退,所以你不能保证任何值或订单的状态。