Без воспроизводимого примера, я должен был предположить в контексте этого кода:
#include <vector>
class SparseMatrix
{
std::vector<double> values = { 5, 8, 3, 6, };
std::vector<std::size_t> rows = { 0, 0, 2, 3, 4, };
std::vector<std::size_t> cols = { 1, 2, 1, 1, };
public:
const std::vector<std::size_t> *get_rowptr() const { return &rows; };
const std::vector<std::size_t> *get_columnindex() const { return &cols; };
const std::vector<double> *get_value() const { return &values; };
};
#include <array>
#include <iostream>
int main()
{
SparseMatrix matrix;
std::array<double, 4> result{};
std::array<double, 4> vector1{ 1, 2, 3, 4 };
#pragma omp parallel for
for (int i = 0; i < matrix.get_rowptr()->size() - 1; ++i)
{
for (int j = matrix.get_rowptr()->operator[](i); j < matrix.get_rowptr()->operator[](i + 1); ++j)
{
result[matrix.get_columnindex()->operator[](j)] += matrix.get_value()->operator[](j) * vector1[i];
}
}
for (auto const& i: result)
std::cout << i << " ";
std::cout << '\n';
}
С некоторыми подходящими переменными мы можем упростить код, чтобы мы видели, что происходит:
auto const& rows = *matrix.get_rowptr();
auto const& cols = *matrix.get_columnindex();
auto const& values = *matrix.get_value();
#pragma omp parallel for
for (std::size_t i = 0; i < rows.size() - 1; ++i)
{
for (std::size_t j = rows[i]; j < rows[i+1]; ++j)
{
result[cols[j]] += values[j] * vector1[i];
}
}
Теперь мы можем видеть в теле цикла, который мы присваиваем записи результата, в которую другие потоки также могут записывать.Нам нужно сериализовать доступ к result[cols[j]]
, чтобы только один поток одновременно выполнял +=
.Мы можем сделать это, пометив эту операцию как неделимую, используя ключевое слово OMP atomic
:
#pragma omp parallel for
for (std::size_t i = 0; i < rows.size() - 1; ++i)
{
for (std::size_t j = rows[i]; j < rows[i+1]; ++j)
{
auto& dest = result[cols[j]];
auto const term = values[j] * vector1[i];
#pragma omp atomic
dest += term;
}
}