繁体   English   中英

std :: atomic访问是否充当内存屏障?

[英]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最初是真的 更新线程执行以下语句,并在更新原子标志之前中断:

if (useMapA) {
    mapB = std::move(*latestMap);

现在,读者线程仅评估原子标志:

bool r1 = useMapA; // r1==true

继续更新线程并将原子标志设置为false 一秒钟后,更新线程评估原子标志:

if (useMapA) { // condition is false

现在,读者线程继续。 两个线程都访问mapA ,并且至少有一个线程写入数据结构。 这意味着,存在数据竞争 ,这意味着程序的行为是未定义的,无论此数据竞争是否真的发生。

如果每隔15分钟调用一次updateMap会有什么变化? 除非在这15分钟内发生一些额外的同步,否则它仍然是数据竞争,因为C ++标准在第二和第15分钟之间没有区别。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM