首页 > 解决方案 > 内存泄漏 C++ 线程

问题描述

我有一个问题,可能是 C++ 线程中的内存泄漏。我收到代码 11 的运行时错误。我正在编写一个优化算法,旨在优化 2D 反应器的参数。它生成重整函数的实例,该函数创建重整器对象。重整器有 2 个不同的参数,它们在单个重整器中可以局部不同,并从主函数传递给重整函数。为了指定,每个重整器被划分为指定数量的区域(每个重整器中的尺寸和位置相同),并且每个区域可以具有不同的参数。因此,2 个向量中的每一个的大小等于 [NUMBER OF REFORMERS] * [NUMBER OF ZONES]。然后,重整函数创建 Segment 对象,其数量等于区域的数量。

我认为这里的问题是线程试图同时访问同一个向量,我真的很感激这个问题的解决方案。

评论:

  1. 如果我更改 main.cpp 以用通常的循环替换线程,则不会返回错误。
  2. 如果我在 set_segments 函数中注释掉 setProp 方法,则不会返回错误(带线程)。

这里强烈推荐线程,因为单个Reformer的计算时间很长,而且我可以访问多核计算单元。

为了澄清,我将用一个最小的可重现示例来解释所有内容:

输入.h

#include <iostream>
#include <fstream>
#include <vector>
#include <thread>
int reactor_no = 2;    // number of reformers
int zones_X = 5;       // number of zones in a single reformer, X direction
int zones_Y = 2;       // number of zones in a single reformer, Y direction
double dim_X = 0.5;    // reactor's length    
double dim_Y = 0.2;    // reactor's height
double wall_t = 0.1;   // thickness of the reactor wall
size_t zones = zones_X * zones_Y;

改革者.h:

#include "input.h"
class Reformer {
public:
    Reformer() {}
    Reformer(const double& L, const double& Y, const double& wall_t, 
                        const int& zones_X = 1, const int& zones_Y = 1) {
        length_ = L;
        height_ = Y;
        zonesX_ = zones_X;
        zonesY_ = zones_Y;
        wall_thickness_ = wall_t;   

        dx_ = length_ / static_cast<double> (zonesX_);
        dr_ = height_ / static_cast<double> (zonesY_);
    }

private:
    double wall_thickness_;         // wall thickness (m)
    double length_;                 // recactor length (m)
    double height_;                 // reactor height (m) (excluding wall thickness)
    int zonesX_;                    // number of segments in the X direction
    int zonesY_;                    // number of segments in the Y direction 
    double dx_;                     // segment width    (m)
    double dr_;                     // segment height (m)
}

段.h:

#include "input.h"
class Segment{
public:
    Segment() : Segment(0, 0) {}

    Segment(int i, int j) {
        i_ = i;
        j_ = j;
    }

    void setXR(const double& dx, const double& dr, const int& SL, const int& SR) {
        x0_ = i_ * dx;
        x1_ = x0_ + dx;

        r0_ = j_ * dr;
        r1_ = r0_ + dr;

        if (i_ == SL - 1) {
            x1_ = length;
        }

        if (j_ == SR - 1) {
            r1_ = radius;
        }   
    }

    void setWall() {
        x0_ = 0;
        x1_ = length;

        r0_ = radius;
        r1_ = radius + wall_t;
    }

    void setProp(const double& por, const double& por_s, const bool& cat) {
        porosity_ = por;
        catalyst_ = cat;
    }
private:
    size_t i_;          //segment column no.
    size_t j_;          //segment row no.

    double x0_;         //beginning of segment - x coordinate (m)
    double x1_;         //ending of segment - x coordinate (m)
    double r0_;         //beginning of segment - r coordinate (m)
    double r1_;         //ending of segment - r coordinate (m)

    int catalyst_;      //1 - catalytic, 0 - non-catalytic
    double porosity_;   //porosity (-)

};

主.cpp:

#include "input.h"
int main() {

    int zones = zones_X * zones_Y;

    size_t pop_size = reactor_no * zones;
    std::vector<int> cat;
    cat.reserve(pop_size);
    std::vector<double> porosity;
    porosity.reserve(pop_size);                // the values in the vectors are not important, therefore I will just fill them with 1s
    for (int i = 0; i < pop_size; i++) {
        cat[i] = 1;
        porosity[i] = 1.0;
    }

    std::vector<std::thread> Ref;
    Ref.reserve(reactor_no);
    for (k = 0; k < reactor_no; k++) {
        Ref.emplace_back(reforming, k, cat, porosity);
    }

    for (auto &X : Ref) { X.join(); }
}

改革.cpp:

    #include "input.h"

void reforming(const int m, const std::vector<int>& cat_check, const std::vector<double>& por) {                                           
    Reformer reactor(length, radius, wall_t, zonesX, zonesY);

    std::vector<Segment> seg;     // vector holding segment objects                                                                  
    seg.reserve(zones);

    set_segments(seg, reactor, zones, m, por, por_s, cat_check);

}

set_segments 函数:

#include "input.h"
void set_segments(std::vector<Segment> &seg, Reformer &reac, const int m, 
                     const std::vector<double> &por, const std::vector<int> &check) {
    int i, j, k, n;

    double dx = dim_X / static_cast<double> (zones_X);
    double dy = dim_Y / static_cast<double> (zones_Y);

    std::vector<Segment*> ptr_seg;
    ptr_seg.reserve(zones);

    k = 0;
    for (i = 0; i < zones_X; i++) {
        for (j = 0; j < zones_Y; j++) {
            n = m * zones + (i * zones_Y + j);
            seg.emplace_back(Segment(i, j));
            seg[k].setProp(por[n], check[n]);
            seg[k].setXR(dx, dy, zones_X, zones_Y);
            k++;
        }
    }

}  

标签: c++multithreadingmemory-leaksparallel-processingstdvector

解决方案


将 std::ref() 添加到重构函数调用参数解决了这个问题。

for (k = 0; k < spec_max; k++) {
        Ref.emplace_back(reforming, k, std::ref(cat), std::ref(porosity));
}

推荐阅读