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

时间:2014-08-15 18:33:00

标签: c++ multithreading stl

我有一个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?
}

2 个答案:

答案 0 :(得分:3)

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

请在这里查看:Is copy thread-safe?

但是,如果您设法创建一致的副本,我不明白为什么不...

答案 1 :(得分:2)

在该代码中有undefined behavior,因为您返回对局部变量的引用。一旦函数返回,这个locla变量将被破坏,你现在可以引用一个被破坏的对象。

如果您想要返回副本,那么您必须按值返回,这样就好了。

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

如果你使用C++11 standard thread library中的互斥锁和锁定,你不需要显式解锁,那么互斥锁将在解锁时解锁。