首页 > 解决方案 > 如何避免文件变量成为 OpenMP 中的竞争条件(离散元方法模拟)

问题描述

我正在进行离散元法模拟,现在正在进行并行程序。到目前为止,我已经成功地在 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);  

LeftMirrorVecstatic vectors和 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

标签: c++openmpxcode10

解决方案


推荐阅读