Как избежать файловых переменных, являющихся условием гонки в OpenMP (моделирование методом дискретных элементов) - PullRequest
0 голосов
/ 21 января 2019

Я выполняю моделирование методом дискретных элементов, и сейчас я прохожу параллельную программу. До сих пор я успешно запускал код в 4 и более ядрах, но полученные данные были явно не верны. Я выяснил, что проблема произошла из-за состояния гонки

Я использовал некоторые векторы области файла (объявленные в классе с помощью общедоступного статического вектора) для восстановления информации, связанной с частицами (положение, скорость, сила). И в моем классе обнаружения контакта он также включает в себя другой класс.
У меня вопрос, как защитить переменные области видимости файлов и объекты без условия гонки?

Вот то, как я использовал и демонстрацию моего кода:
Добавьте threadprivate после того, как я объявил статические переменные, как в примере ниже

Myclass{
    public: 
        static <vector> ContactList;
        static <vector> LeftMirrorVec;
        static <vector> RightMirrorVec;
        ...
        #pragma omp threadprivate(ContactList,LeftMirrorVec,RightMirrorVec)

и этот метод вызывает постоянное накопление памяти, я не знаю, что случилось. Ниже приведена часть, я использую эти статические векторы в main.cpp

#pragma omp parallel
        {
            int right;
            int left;
            int middle;
            int SlaveCount;
            double particleOverlap;
            double tempXmaxParticles;
            double tempXminParticles;

#pragma omp for schedule(dynamic,3) private(right,left,middle,SlaveCount,particleOverlap,tempXmaxParticles,tempXminParticles) reduction(+:KE)
for(int MasterCount=0; MasterCount<DataCollector::ParVec.size(); MasterCount++){
            int ID = omp_get_thread_num();
            //right zone detect
            for(right=0; right<DataCollector::RightMirrorVec.size();right++){
                if(DataCollector::ParVec[MasterCount].getParPosx()<Boundary::Xmax && DataCollector::ParVec[MasterCount].getParPosx()>Boundary::Xmax-DataCollector::ParVec[MasterCount].getParRadius()-DataCollector::RightMirrorVec[right].getParRadius()){
                    SlaveCount = DataCollector::RightMirrorVec[right].getparID(); //get the right mirror particle id
                    tempXmaxParticles = DataCollector::ParVec[SlaveCount].getParPosx(); //restore the original position
                    DataCollector::ParVec[SlaveCount].setParPosx(DataCollector::RightMirrorVec[right].getParPosx()); // move to the mirror pos
                    particleOverlap = DataCollector::ParVec[MasterCount].getParRadius()+DataCollector::ParVec[SlaveCount].getParRadius()-sqrt((DataCollector::ParVec[SlaveCount].getParPosx()-DataCollector::ParVec[MasterCount].getParPosx())*(DataCollector::ParVec[SlaveCount].getParPosx()-DataCollector::ParVec[MasterCount].getParPosx())+(DataCollector::ParVec[SlaveCount].getParPosy()-DataCollector::ParVec[MasterCount].getParPosy())*(DataCollector::ParVec[SlaveCount].getParPosy()-DataCollector::ParVec[MasterCount].getParPosy())); // overlap between real and right ghost particles
                    if(particleOverlap>0){
                        LSDmodel RightModel(time,input,MasterCount,SlaveCount,particleOverlap);
                    }
                    particleOverlap=0;
                    DataCollector::ParVec[SlaveCount].setParPosx(tempXmaxParticles);  

static vectors LeftMirrorVec и RightMirrorVec будут повторно входить в различные потоки для обнаружения контактов.

И еще один вопрос, у меня есть объект, объявленный в моем классе обнаружения контактов, как показано ниже

 LSDmodel::LSDmodel(TimeZone time,InputZone input, int MasterCount, int SlaveCount){
    double DampTemp = -log(input.getRestituition())/pi;
    DampRatio = DampTemp/sqrt(1+DampTemp*DampTemp);
    if( MasterCount!=SlaveCount){
        ContactParameter contactpara;
        int ContactType =1;
        double distx = DataCollector::ParVec[SlaveCount].getParPosx()-DataCollector::ParVec[MasterCount].getParPosx();
        double disty = DataCollector::ParVec[SlaveCount].getParPosy()-DataCollector::ParVec[MasterCount].getParPosy();
        double particleOverlap = DataCollector::ParVec[SlaveCount].getParRadius()+DataCollector::ParVec[MasterCount].getParRadius()-sqrt(distx*distx+disty*disty);
        if(particleOverlap > 0){
            static Material material(MasterCount,SlaveCount,ContactType);
            #pragma omp threadprivate(material,contactpara)
            contactpara.setUnitNormDir(MasterCount, SlaveCount);
            ...

Как видите, я объявил два разных конструктора из разных классов. И далее я использую экземпляры из них.
Мой второй вопрос: будут ли конструкторы contactpara и material создаваться разными потоками без взаимного влияния?
Если нет, пожалуйста, дайте мне несколько советов, как справиться с этим вопросом. И если требуется более подробная информация, пожалуйста, скажите мне, спасибо.

...