由于我的编译器仍不支持c++11和std::atomic,我被迫通过ldrex-strex对其进行手动实现。
我的问题是:使用ldrex和strex以“原子方式”读取修改写入int64_t的正确方法是什么?
这样的简单解决方案似乎行不通(其中一个STREXW始终返回1):
volatile int64_t value;
int64_t temp;
do
{
int32_t low = __LDREXW( (uint32_t *)&value );
int32_t high = __LDREXW( ((uint32_t *)&value)+1 );
temp = (int64_t)low | ( (int64_t)high<<32);
temp++;
} while( __STREXW( temp, (uint32_t *)&value) | __STREXW( temp>>32, ((uint32_t *)&value)+1) );
我在手册中找不到关于多个连续的LDREX或STREX指令指向不同地址的内容,但我认为应该是允许的。
否则,在某些情况下,多个线程将无法更改两个不同的原子变量。
ldrd
和strd
与自旋锁和/或结构,例如环形缓冲区,在单个读取器/写入器方面固有安全性,并且已经多年用于主线/中断。请参见:Donald Knuth,《计算机编程的艺术》和 Stefani Seibold等人的Linux kfifo.h。我认为她在这个实现上做得很好,但它依赖于一些狂热者可能不喜欢的溢出条件。 - artless noise