Я пытаюсь перебрать карту, содержащую уникальные указатели в качестве значений.Вот реализация.Код компилируется, без проблем.
#include <iostream>
#include <map>
#include <memory>
#include <vector>
#include <omp.h>
class test_class
{
public:
test_class(int Id, double Td)
{
mId = Id;
mTd = Td;
}
void update(double Utd)
{
mTd += Utd;
}
void print()
{
std::cout<<"test_class :: "<<mId<<" Td :: "<<mTd<<std::endl;
}
private:
double mTd;
int mId;
};
typedef std::map< int, std::unique_ptr<test_class> > MapType;
int main() {
MapType map_u_prt;
std::vector<int> vec_ids = {1,2,6,5,8,4,3,6,9,2,4,2,5,8,5,7,7,1,4,3,2,7,8,9,9,3,3,5,7,7,9,9,2,3,4,3,4,3,4,3,6};
int id = 0;
#pragma omp parallel for num_threads(4)
for(unsigned int i=0; i<vec_ids.size(); i++)
{
int threadnum = omp_get_thread_num();
int numthreads = omp_get_num_threads();
id = vec_ids[i];
#pragma omp critical
std::cout<<"thread :: "<<threadnum<<" , total num thread :: "<<numthreads<<" ---- accessing :: "<<id<<std::endl<<std::flush;
auto itr = map_u_prt.find(id);
if(itr == map_u_prt.end())
{
map_u_prt[id] = std::make_unique<test_class>(id, 1.0);
}
map_u_prt[id]->update(1.0);
}
for (const auto& it : map_u_prt)
{
std::cout<<"##### "<<std::endl;
it.second->print();
}
std::cout<<"##### SUCCESSFUL ##### "<<std::endl;
return 0;
}
Но когда я запускаю код, я получаю случайные ошибки сегмента.И я пытаюсь понять, почему это происходит.Я вроде вижу, почему это происходит (пожалуйста, исправьте меня, если я ошибаюсь), но не ясно, как решить эту проблему.
auto itr = map_u_prt.find(id);
В приведенной выше строке поиск на карте не синхронизирован,Это означает, что один поток может видеть, что есть запись для определенного идентификатора, в то время как другой поток не завершил вставку указателя, и, таким образом, предыдущий поток получит нулевой объект и ошибки сегмента.
Есть ли способ преодолеть эту проблему?Я могу поставить проверку и вставку в критическую область, но в большом цикле (миллион записей в vec_ids) это узкое место.