复制/修改STL容器的副本是线程安全的

Is is thread-safe to copy/modify a copy of an STL container?

本文关键字:副本 线程 安全 修改 STL 复制      更新时间:2023-10-16

我有一个将从多个线程修改的std::map,并且我有一个互斥锁来锁定这些写操作。但是,在长时间运行的操作期间必须偶尔使用映射,并且在整个操作期间持有锁并阻塞所有这些写操作是不好的。

我有两个问题:

  • 是线程安全的执行该操作的副本上的地图,而其他线程正在写原来的?
  • 是线程安全的复制地图,而其他线程正在改变它?
例如:

class Foo {
    void writeToMap(Bar &bar, Baz &baz) {
        // lock mutex
        map[bar] = baz;
        // unlock mutex
    }
    std::map<Bar, Baz> getMapCopy() {
        // lock mutex (Is this necessary?)
        std::map<Bar, Baz> copy (map);
        // unlock mutex
        return copy;
    }
    std::map<Bar, Baz> map;
};
void expensiveOperation(Foo &f) {
    std::map<Bar, Baz> mapCopy = f.getMapCopy();
    // Can I safely read mapCopy?
}

听起来好像复制操作本身不是线程安全的,问题是复制64位值的原子性。您复制前4个字节,而第二个4被另一个线程修改,留下不一致的8个字节。

请查看这里:复制线程安全吗?

如果你设法创建一个一致的副本,然而,我不明白为什么不…

在该代码中有未定义行为,因为您返回对局部变量的引用。一旦函数返回,这个局部变量将被解构,现在您就有了一个对被解构对象的引用。

如果你想返回一个副本,那么你必须返回的值,所以它将是例如

std::map<Bar, Baz> getMapCopy() {
    return map;
}

如果您使用c++ 11标准线程库中的互斥锁,则不需要显式解锁,互斥锁将随着锁的销毁而解锁。