【发布时间】: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可能效率不是很高。