std :: map上可能的线程不安全操作

时间:2015-12-15 13:14:45

标签: c++ stl thread-safety

STL不保证其集合的线程安全。但我想知道以下代码是否真的有效。

一个线程通过调用[]运算符调用地图m上的非const运算,但是使用地图上已存在的键。据我所知,这只是调用find()并返回对gcc中迭代器的引用。另一个线程同时将const迭代器保存到m。

问题是:断言会失败吗?

void doBracket(std::map<int, int>& m) {
  const auto&  val = m[0];
  std::cerr << val << std::endl;
}


void doIter(const std::map<int, int>& m){
  auto zeroIter = m.find(0);
  auto oneIter = m.find(1);
  auto twoIter = m.find(2);
  assert(zeroIter->second == 0);
  assert(oneIter->second == 1);
  assert(twoIter->second == 2);
}

int main() {
  std::map<int, int> m = {{0, 0}, {1, 1}, {2, 2}};
  std::thread mutateThread {doBracket, std::ref(m)};
  std::thread constThread  {doIter, std:ref(m)};
  mutateThread.join();
  constThread.join();
}

这是stl_map的作用:

   operator[](const key_type& __k)
      {
        // concept requirements
        __glibcxx_function_requires(_DefaultConstructibleConcept<mapped_type>)

        iterator __i = lower_bound(__k);
        // __i->first is greater than or equivalent to __k.
        if (__i == end() || key_comp()(__k, (*__i).first))
                 //handle this case

        return (*__i).second;
      }

2 个答案:

答案 0 :(得分:1)

看来你已经确定了一个可以超越标准的地方,了解实施情况。但是,与使用find()代替operator[]()的保证安全方法相比,此方法没有优势。

补充工具栏:我个人认为std::map::operator[]()几乎无用。我总是希望使用find()insert()或其他内容。

答案 1 :(得分:1)

如果你看一下http://www.cplusplus.com/reference/map/map/operator%5B%5D/,就会说map :: operator []:

  

迭代器有效期

     

没有变化。

     

数据竞赛

     

访问容器,并可能进行修改。   该函数访问一个元素并返回一个可用于修改其映射值的引用。同时访问其他元素是安全的。   如果函数插入一个新元素,则同时迭代容器中的范围是不安全的。

根据这一点,唯一可能不安全的情况是“如果函数插入新元素,则同时迭代容器中的范围”。由于您没有进行任何插入,因此结论必须是您的代码是安全的。