2016-08-09 18 views
0

我有一个带有两个线程的单核CPU(ARM Cortex M3,32位)。假设以下情况:是在单核CPU原子上写入变量吗?

// 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的行为有何不同?

+3

对_atomic_访问使用'std :: atomic '。 –

+2

您的代码具有完全可移植性和独立于编译器的*未定义行为*。所有的实现都可以完全自由地做任何他们想做的事情。 –

+0

@πάνταῥεῖ。不幸的是,由于编译器的限制,我无法访问它(例如,没有C++ 11)。但除此之外,这将是一条路。 –

回答

2

这取决于CPU,主要是,虽然在预C11涉及多个线程理论什么是最好的实现定义,在最坏的情况不确定的行为,因此编译器可能会做任何事情。

如果你可以忽略疯狂的编译器做愚蠢的事情,并假定编译器将使用CPU的设施,以合理的方式,它主要取决于什么CPU的支持。

Cortex-M3的是一个32位CPU,一个32位总线和没有FPU。因此读取和写入32位和更小的值通常是原子的。然而,double是64位的,所以任何双/双写操作都会涉及两条指令并且是非原子的。因此,如果一个线程读取而另一个线程读取,则可能会从一个值减半,而另一个值减半。

现在在你的具体的例子,值1.0和2.0是其下半部分都是0,所以“混合”是无害的,但其他的值不会有这种行为。

+0

我现在很困惑。如果我坚持两个32位或更低的文字是原子? (不受任何标准保证,但在实践中) –

+0

实际上,是32位和更小的整数将是原子。当然,对多元变量的访问可能会重新排序,除非您在它们之间粘贴(编译器特定的)屏障。 –

+0

我一直认为32位是对记忆地址大小的引用。这意味着可以处理2^32位。这是否也构成可寻址内存大小块的下限? –

1

该操作的评估顺序为:不保证从左到右,即使它们是,它们不是原子的,如果你尝试读取和写入同时发生段错误(它们可以执行多个周期并且上下文切换可以打断它)。

在arm上,特别是读取和写入在cpu上的队列中,它们可以自由地重新排序(除去过去的内存障碍),即使在不重新排序内存的cpu上,编译器也可以自由地重新排序。没有任何东西阻止你的任务,并且阅读被向前或向后移动,所以你不能保证任何值或顺序的状态。

相关问题