Открыть цикл MP над картой уникальных указателей - PullRequest
0 голосов
/ 04 октября 2018

Я пытаюсь перебрать карту, содержащую уникальные указатели в качестве значений.Вот реализация.Код компилируется, без проблем.

#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) это узкое место.

...