当我不添加/删除键时,可以并行使用std :: map吗?

我有一个使用很多std::map结构的程序。现在,我想将它们与多个线程一起使用,并假定插入或删除键可能会更改整个数据结构并并行破坏它。但是当我不添加新密钥时,应该没事吧?

以下程序显示了我想做什么:

#include <omp.h>                                                                

#include <iostream>                                                             
#include <map>                                                                  

int main(int const argc,char const *const *const argv) {                          
  // Take a map and allocate the elements,but not fill them at this point.        
  std::map<int,int> map;                                                          
  int size = 10000;                                                                
  for (int i = 0; i < size; ++i) {                                                 
    map[i];                                                                        
  }                                                                                

  // Go through the elements in parallel and write to them,but not create any  
  // new elements. Therefore there should not be any allocations and it should  
  // be thread-safe.                                                               
#pragma omp parallel                                                               
  {                                                                                
    int const me = omp_get_thread_num();                                           
#pragma omp for                                                                    
    for (int i = 0; i < size; ++i) {                                               
      map[i] = me;                                                                 
    }                                                                              
  }                                                                                

  // Now all threads access all the elements of the map,but as the map is not  
  // changed any more,nothing bad should happen.                               
#pragma omp parallel                                                               
  {                                                                                
    int const me = omp_get_thread_num();                                           
    int self = 0;                                                                  

    for (int i = 0; i < size; ++i) {                                               
      if (map[i] == me) {                                                          
        ++self;                                                                    
      }                                                                            
    }                                                                              

#pragma omp critical(cout)                                                         
    std::cout << "Thread " << me << " found " << self << " entries.\n";            
  }                                                                                
}

然后用以下代码进行编译:

$ g++ -fopenmp -O3 -Wall -Wpedantic -g -fsanitize=address -o concurrent-map concurrent-map.cpp

这似乎可以在四个线程上正常工作。如果我注释掉第一个for循环并让线程填充地图,则它会由于我的期望而导致分段错误。

当然,我无法以这种方式证明std::map是线程安全的,但至少不能证明是负面的。我可以并行使用std::map吗?

ldg2000 回答:当我不添加/删除键时,可以并行使用std :: map吗?

我认为使用map[i]对于所有C ++实现都不是线程安全的,即使它没有插入新元素也是如此。该标准不要求operator[]不受关联容器的数据竞争:

C ++ 17标准草案的[container.requirement.dataraces]/1部分包含一个函数列表,即使它们不是const也不应引起数据争用。该列表包括findat,但不包括operator[]

因此,您需要使用findat而不是operator[]。特定的实现可能会提供更强的保证,并且可能在map[i]不插入新元素的情况下实现,但是您需要使用编译器/标准库文档进行检查。

除此之外,对容器的不同元素进行访问(甚至进行修改)总是可以的(vector<bool>除外),请参阅标准的下一段。

,

编辑: 由于无法保证operator[]不会修改结构,因此无法保证它可以正常工作。最好使用at()find()

据我了解C ++标准和OpenMP文档-这是安全的。首先,只要您不进行修改迭代器的操作,并行修改就可以了。

第二个问题是写在不同线程中的数据在其他线程中是否可见。幸运的是,OpenMP有相当不错的文档,其中指出内存同步是隐式发生的:

  

在每个隐式任务的任务区域的退出处;

本文链接:https://www.f2er.com/3166949.html

大家都在问