2

访问同一个数组的不同元素会造成数据竞争吗?

我有一个带有矩阵接口的数组的“矩阵”包装类,我为它编写了一个标量函数的并行乘法。

我将CTPL库用于线程池。

我知道从线程写入通过引用传递的数组单元不是数据竞争(如果我错了,请纠正我)所以我决定将一个单元从数组传递给函数,这样我就可以将乘法结果写入单元格本身,而不是通过传递对数组和索引的引用,所以我可以避免数据竞争。

我运行该函数 10k 次,结果甚至一次都没有不同,但是我使用的消毒剂(Cmake 标志中的“ -fsanitize=thread -fPIE -pie -g ”)仍然提醒我在我创建的行上存在数据竞争线程池。

是消毒剂弄错了还是我真的在某个地方经历了数据竞争?

以下是与问题相关的代码片段:

包装:

class Matrix {
protected:
    int width;
    int height;
    double* matrix;

public:

    Matrix(int m, int n);

    Matrix(int m, int n, const std::vector<double>& values);

    int get_width() {
        return width;
    }

    int get_height() {
        return height;
    }

    double get_element(int row_num, int col_num);

    void set_element(int row_num, int col_num, double el);

    double* get_cell_ref(int row_num, int col_num);
};


方法实现:

Matrix::Matrix(int m, int n) {
    assert(m > 0 && n > 0);
    matrix = new double[m * n]{0};
    width = n;
    height = m;
}

Matrix::Matrix(int m, int n, const std::vector<double>& values) {
    assert(m > 0 && n > 0 && values.size() == m * n);
    matrix = new double[m * n];
    width = n;
    height = m;
    for (int i = 0; i < m * n; ++i) {
        matrix[i] = values[i];
    }
}

double Matrix::get_element(int row_num, int col_num) {
    assert(check_valid(row_num, col_num, get_width(), get_height()));
    return matrix[col_num + get_width() * row_num];
}

void Matrix::set_element(int row_num, int col_num, double el) {
    assert(check_valid(row_num, col_num, get_width(), get_height()));
    matrix[col_num + row_num * get_width()] = el;
}

double* Matrix::get_cell_ref(int row_num, int col_num) {
    int idx = col_num + get_width() * row_num;

    return &matrix[idx];
}

据称有数据竞争的函数:

Matrix* scalar_multiply_parallel(Matrix* a, double mul, int threadN) {
    auto* b = new Matrix(a->get_height(), a->get_width());

    ctpl::thread_pool thr_pool(threadN);
    std::vector<std::future<void>> futures(a->get_height() * a->get_width());

    for (int i =0; i < a->get_height(); i++) {


            for (int j =0; j < a->get_width(); j++) {
                int idx = j + a->get_width() * i;

                auto util = [&a, &b, i, j, mul](int) {
                    //b->set_element(i, j, a->get_element(i, j) * mul);
                    double *cell;
                    cell = b->get_cell_ref(i, j);
                    *cell = a->get_element(i, j) * mul;
                };

                futures[idx] = thr_pool.push(util);
            }

    }

    for (auto& f: futures) {
        f.get();
    }

    return b;
}
4

0 回答 0