在多线程上下文中安全使用映射中的引用

Safe use of a reference in a map in multi-threaded context

上下文

我有一个 class(比方说 Foo)管理一些集中资源作为静态地图中的历史记录,具有读取它们的访问器和添加新数据的功能(有无法删除密钥):

class Foo
{
  private:
    static std::map<std::string,MyDataStructure> data;
  public:
    static const MyDataStructure& getData(const std::string& key)
    {
      assert(Foo::data.count(key) > 0); // Must exist
      return Foo::data[key];
    }
    static void addData(const std::string& key, const MyDataStructure& d)
    {
      assert(Foo::data.count(key) == 0); // Can not already exist
      Foo::data[key] = d;
    }
};

为了避免并发问题,我添加了一个我这样管理的互斥量:

class Foo
{
  private:
    static std::map<std::string,MyDataStructure> data;
    static boost::mutex mutex_data;
  public:
    static const MyDataStructure& getData(const std::string& key)
    {
      boost::mutex::scoped_lock lock(Foo::mutex_data);
      assert(Foo::data.count(key) > 0); // Must exist
      return Foo::data[key];
    }
    static void addData(const std::string& key, const MyDataStructure& d)
    {
      boost::mutex::scoped_lock lock(Foo::mutex_data);
      assert(Foo::data.count(key) == 0); // Can not already exist
      Foo::data[key] = d;
    }
};

我的问题

  1. 我的第一个问题是关于 getData 返回的对 Foo::data 的引用:这个引用是在互斥锁的范围之外使用的,那么它可能有问题吗?是否有可能由于另一个访问添加数据而丢失引用?简而言之:地图中的引用是否始终相同?
  2. 如果是,addData 中是否需要 assert?如果我更改链接到地图中现有键的数据,参考会更改吗?
  3. getData需要锁吗?如果 std::map 已经是多线程安全的,我认为可能不会。
  1. 是否可能由于另一个访问添加数据而丢失引用?简而言之:地图中的引用是否始终相同?

Lifetime of references in STD collections

"for std::map, the references are valid as long as you don't clear the map, or erase the specific referenced element; inserting or erasing other elements is fine."

  1. 如果我更改链接到地图中现有键的数据,引用是否会更改?

根据上述规则,不...修改映射中已有的引用只是调整同一地址的位。 (只要您不通过删除密钥然后再次重新添加该密钥来实施修改。)

  1. getData 是否需要锁?如果 std::map 已经是多线程安全的,我认为可能不会。

C++11 STL containers and thread safety

所以需要锁,因为映射结构的 "internal wiring" 在 addData() 的插入过程中可能会发生变化...在查找遍历 getData()没有守卫

但是,如果您手头有参考,您可以在添加或删除过程中读取或写入已经存在的 MyDataStructure 参考之一。只是从地图到参考的导航过程需要确保在导航期间没有人在写。