std::原子加载和存储都需要吗
Are std::atomic loads and stores both required?
根据本文:
任何时候,两个线程同时对一个共享变量进行操作,并且其中一个操作执行写操作,则两个线程都必须使用原子操作。
但是,如果一个优先级较低的线程是写入程序,而一个优先级较高的线程是读取器,那么低优先级线程是否需要强制执行原子存储?在我看来,只有优先级较高的线程才需要强制执行原子负载:
#include <atomic>
std::atomic<T*> ptr; // assume initialized to some non-null value
void highPriThreadFcn(void)
{
T* local_ptr = ptr.load(); // need atomic load here in case lowPriThread write/store was interrupted
}
void lowPriThreadFcn(T* some_ptr)
{
ptr = some_ptr; // do I need an atomic store here? I'd think not, as ptr is not written to by highPriThread
}
类似的问题也适用于"反向"情况(在高优先级线程中写入,从低优先级线程中读取(:
void highPriThreadFcn(T* some_ptr)
{
ptr = some_ptr; // do I need an atomic store here? I'd think not, as write to ptr cannot be interrupted
}
void lowPriThreadFcn(void)
{
T* local_ptr = ptr.load(); // need atomic load here in case read/load was interrupted
}
不能对原子变量执行非原子存储或加载。API确保没有办法尝试。你所谓的"非原子商店",
ptr = some_ptr;
实际上是一个顺序一致的原子存储。请参阅cppreference上的atomic::operator=。
顺便说一句,如果您正在考虑将原子变量更改为非原子变量,在该变量上只执行一些原子操作:请不要这样做。每当加载和存储到同一内存位置是"潜在并发的"时,标准要求它们都是原子的。否则,行为是未定义的。这意味着编译器可以以破坏代码的方式进行"优化"。一个线程的优先级是否比另一个线程"高"并不影响这一点。
标准被设计为可在具有奇怪和奇怪内存语义的平台上得到支持。为了适应这一点,它避免了对实现如何处理任何结构施加任何要求,而这些结构对于一些平台来说可能难以预测地处理。一些实现将其解释为在这种情况下以任意和不可预测的方式行事的许可证,即使是针对自然支持更强内存语义的平台。这有助于某些类型的优化,但可能会使程序员有必要采取明确的行动来束缚优化器的手脚,在某些情况下,如果编译器提供(和程序员利用(比标准要求更强的语义,则会使事情的效率降低。
作为一个可能出现问题的情况的例子,可以考虑以下内容:
extern int foo;
int x=foo;
.... some code that modifies neither x nor foo
int y=x;
.... some code that modifies neither y nor foo (but might modify x)
doSomething(x, y);
在假设foo
必须等于y
在原始赋值时的值的情况下,优化编译器可以用doSomething(x, foo)
替换最后一个函数调用,这是完全合理的。该标准的作者没有使用允许有界非决定论的抽象模型,而是拒绝强制要求对对象值意外变化的影响提供任何形式的行为保证。
- std::原子加载和存储都需要吗
- 原子加载和存储与内存顺序放宽
- 存储并重新加载随机数生成器状态
- std::atomic_flag不提供加载或存储操作有什么缺点吗?(自旋锁定示例)
- C++ 多线程原子加载/存储
- 在ARM上加载并存储重新排序
- 是否可以在条件之前对加载或存储进行重新排序?
- 通过无符号 char 别名进行对象访问,加载和存储时会发生什么?
- 保存和加载类数据存储在C 中的二进制文件中
- gcc矢量扩展中未对齐的加载/存储
- 当某些错误可以接受时,顺序加载存储原子的内存顺序应该是什么
- 加载/存储8位和32位之间的值
- Valgrind:在多线程程序中发现冲突的存储/加载
- AVX:数据对齐:存储崩溃、存储、加载、加载你不
- C 的空间indexex库:从/到磁盘加载/存储主内存rtree
- SSE 向量的对齐和未对齐加载和存储 - 如何减少代码重复
- 修复加载命中存储
- 将临时对象保留在寄存器上以避免虚拟机中的额外存储/加载
- 在磁盘上/从磁盘存储/加载C++对象
- 组合存储/加载连续的原子变量