【问题标题】:(C++) openmp leading to segmentation fault(C++) openmp 导致分段错误
【发布时间】:2022-12-25 07:40:53
【问题描述】:

我刚开始在 C++ 上使用 OpenMP,但遇到了一些问题:

#include <algorithm>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
#include <boost/multiprecision/cpp_int.hpp>

using namespace std;
using boost::multiprecision::cpp_int;

// generates prime numbers under n
vector<int> generatePrime(int n) {
  vector<int> primes;
  for (int i = 2; i <= n; i++) {
    bool isPrime = true;
    for (int j = 0; j < primes.size(); j++) {
      if (i % primes[j] == 0) {
        isPrime = false;
        break;
      }
    }
    if (isPrime) {
      primes.push_back(i);
    }
  }
  return primes;
}

// checks if an integer is a prime number
bool chkPrime(vector<int> vec, vector<int> ref) {
  for (int i = 0; i < vec.size(); i++) {
    if (find(ref.begin(), ref.end(), vec[i]) == ref.end()) {
      return false;
    }
  }
  return true;
}

int main() {
  vector<int> primes = generatePrime(100);
  vector<cpp_int> row(1, 1);
  int maxAlleles = 1000;
  vector<vector<int>> rowPrime;
  for (int alleles = 1; alleles <= maxAlleles; alleles++) {
    vector<cpp_int> row1 = row;
    row1.push_back(0);
    row1.push_back(0);
    vector<cpp_int> row2 = row1;
    vector<cpp_int> row3 = row1;
    vector<cpp_int> rowFinal;
    rotate(row2.begin(), row2.end() - 1, row2.end());
    rotate(row3.begin(), row3.end() - 2, row3.end());

    for (int i = 0; i < row1.size(); i++) {
      // making the next row of the trinomial triangle
      rowFinal.push_back(row1[i] + row2[i] + row3[i]);
    }
    row = rowFinal;

    #pragma omp parallel for
    // for each number in the row, we will make the number into a string and divide it by 2 letters
    // and put it into a vector (splitTwo), starting from the beginning of the string
    for (int num = 0; num < row.size(); num++) {
      string item = to_string(row[num]);
      vector<int> splitTwo;
      int i = 0;

      if (item.length() % 2 == 0) {
        while (i <= item.length() - 2) {
          splitTwo.push_back(stoi(item.substr(i, 2)));
          i += 2;
        }
      }

      else {
        if (item.length() > 2) {
          while (i <= item.length() - 3) {
            splitTwo.push_back(stoi(item.substr(i, 2)));
            i += 2;
          }
        }
        int last_letter = item[item.length() - 1] - '0';
        splitTwo.push_back(last_letter);
      }

      // we are going to push back splitTwo in rowPrime if all items in splitTwo are prime numbers
      if (chkPrime(splitTwo, primes) == true) {
        splitTwo.push_back(alleles);
        splitTwo.push_back(num);
        rowPrime.push_back(splitTwo);
      }
    }
  }
  vector<int> sum;
  for (int k = 0; k < rowPrime.size(); k++) {
    sum.push_back(
      accumulate(begin(rowPrime[k]), end(rowPrime[k]) - 2, 0, plus<int>()));
  }

  int idx = distance(begin(sum), max_element(begin(sum), end(sum)));
  for (int &i : rowPrime[idx]) {
    cout << i << ' ';
  }
  cout << sum[idx] << ' ' << rowPrime.size();
  return 0;
}

当我在上面的代码上使用 pragma omp parallel for 并生成可执行文件时,每次执行代码时都会导致不同的结果:1) 正确输出答案,或 2) 给出 segmentation fault 错误,或 3) 给出Incorrect checksum for freed object 0x7fd0ef904088: probably modified after being freed. Corrupt value: 0x0 malloc: *** set a breakpoint in malloc_error_break to debug 错误。当我删除 pragma omp parallel for 时,它不会给我这些错误。有什么建议么?

【问题讨论】:

  • push_back 不是线程安全的,所以 rowPrime.push_back(splitTwo); 行会导致问题。您可以 1) 使用关键部分,2) 使用用户定义的缩减来保护它。
  • 看起来这就是问题所在。在rowPrime.push_back(splitTwo); 之上添加#pragma omp critical 解决了这个问题。
  • 此代码中存在多个性能问题,使其变慢并阻止其在许多平台上很好地扩展。一个大问题是使用大量向量和字符串引起的分配。另一个问题是循环中向量中的线性搜索:您当然可以使用合并,因为一个向量已排序而另一个可以排序,或者使用快速哈希表(甚至可能为此使用布隆过滤器)。关于您的需求,stoi 可能效率不是很高。

标签: c++ openmp


【解决方案1】:

作为一项实验,我通过 OpenAI 的 ChatGPT 运行了这个问题并得到了以下结果,我相信这是你的问题:

看起来您正在尝试并行化代码的内部循环 使用 OpenMP。您面临的问题是您正在尝试修改 rowPrime 在循环中,这在使用 OpenMP 时是不允许的。

解决此问题的一种方法是使用 OpenMP 的 reduction 子句来 将 rowPrime 的多个私有副本减少为一个全局副本 多变的。以下是如何执行此操作的示例:

#pragma omp parallel for reduction(+: rowPrime) for (int num = 0; num < row.size(); num++) {   string item = to_string(row[num]);  
vector<int> splitTwo;   int i = 0;

  if (item.length() % 2 == 0) {
    while (i <= item.length() - 2) {
      splitTwo.push_back(stoi(item.substr(i, 2)));
      i += 2;
    }   }

  else {
    if (item.length() > 2) {
      while (i <= item.length() - 3) {
        splitTwo.push_back(stoi(item.substr(i, 2)));
        i += 2;
      }
    }
    int last_letter = item[item.length() - 1] - '0';
    splitTwo.push_back(last_letter);   }

  // we are going to push back splitTwo in rowPrime if all items in
splitTwo are prime numbers   if (chkPrime(splitTwo, primes) == true) {
    splitTwo.push_back(alleles);
    splitTwo.push_back(num);
    rowPrime.push_back(splitTwo);   } } ```

This will allow each thread to have its own private copy of rowPrime,
and then the reduction clause will combine all of the private copies
into a single global variable after the loop is finished.

I hope this helps! Let me know if you have any other questions.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多