std::原子访问是否充当内存屏障
Does std::atomic access serve as a memory barrier?
编译器是否可以对原子上的指令进行重新排序,或者原子是否充当内存屏障?再说一遍,在原子指令之后编写的指令能在原子指令之前执行吗?
请参阅以下代码。如果在mapB
更新之前移动了useMapA = false
,并且读取线程开始,我们将使用无效的mapB
。
注意:更新线程每15分钟只发生一次,所以我们有一个结构良好的流程,并且有一种方法可以避免使用昂贵的锁调用!
std::atomic<bool> useMapA;
std::map<string, string> mapA, mapB;
public void updateMap(map<string, string>* latestMap) {
if (useMapA) {
mapB = std::move(*latestMap);
useMapA = false;
} else {
mapA = std::move(*latestMap);
useMapA = true;
}
}
inline map<string, string>& getMap() {
return useMapA ? mapA : mapB;
}
编辑:我感兴趣的交易是100%线程安全的速度(时间=金钱)。这个读取函数需要运行得非常快。你可以假设15分钟足够长,以避免比赛条件,如果这个时间短得多。
在回答您的问题之前,我想展示一下如何使用std::shared_ptr和原子操作轻松实现该功能。下面的实现是高效的并且是线程安全的。阅读器也不需要创建地图的副本。
using string_map = std::map<std::string, std::string>;
std::shared_ptr<const string_map> map;
std::shared_ptr<const string_map> getMap()
{
return std::atomic_load(&map);
}
void updateMap(string_map latestMap)
{
std::shared_ptr<const string_map> temp{
new string_map{std::move(latestMap)}};
std::atomic_store(&map, temp);
}
现在,让我们来看看您的代码。这有点复杂。为了更简单,我们假设每秒钟调用一次updateMap,而不是每15分钟调用一次useMapA最初true。更新线程执行以下语句,并且在更新原子标志之前将被中断:
if (useMapA) {
mapB = std::move(*latestMap);
现在,读取器线程只评估原子标志:
bool r1 = useMapA; // r1==true
更新线程继续,并将原子标志设置为false。一秒钟后,更新线程评估原子标志:
if (useMapA) { // condition is false
现在,读者线程继续。两个线程都访问mapA,并且至少有一个线程写入数据结构。这意味着,存在数据竞赛,这意味着程序的行为是未定义的,无论是否真的发生了的数据竞赛。
如果updateMap每15分钟调用一次,会发生什么变化?除非在这15分钟内进行一些额外的同步,否则这仍然是一场数据竞赛,因为C++标准在1秒和15分钟之间没有区别。
相关文章:
- 我在 IDA 或 dbg 或 olly 上看到的内存是否与我在 RAM 上实时加载的内存相同?
- 访问"std::vector"的保留但未调整大小的内存作为原始内存是否安全?
- 本地分配的内存是否可以用于将来使用?
- 多次分配内存是否一次性需要更多时间?
- 删除矢量的尾部(通过擦除)内存是否有效
- 如何找出内存是否属于堆或堆栈
- C++:提升:托管共享内存是否需要信号量锁
- 在 C/C++ 中在特定地址边界上对齐内存是否仍能提高 x86 性能?
- 检查内存是否在堆上
- C++内存 - 是否需要删除使用 'new' 创建的基元类型变量?
- 如果通过委托给“malloc”的重载“new[]”分配,“释放”内存是否安全
- 分配给 cpp 中定义的全局静态变量的内存是否在 C++ 中删除其类的实例后释放
- 我的 265GB RAM 笔记本电脑上的内存是否超过 8GB
- 在动态内存分配中,在程序终止并且忘记释放内存后,该内存是否保持分配状态
- 这些二维数组(C++)的内存是否不足
- 如果我在 for 中声明一个对象,它的内存是否会在那之后被释放?
- 二进制搜索树(如何在插入时检查内存是否不足)
- 用new重新分配内存是否安全
- 在构造函数初始化列表中分配内存是否存在任何问题
- 内存映射内存是否可能