c++ - 添加#pragma loop 后出现段错误

标签 c++ arrays segmentation-fault

我遇到了一点麻烦。我不确定我是否能理解它。 所以,我有一些代码。我正在尝试为代码中的几个循环添加 #pragma loop(hint_parallel(8)) 语句。 当我使用必要的编译选项编译它时,实际上是这样的:

gcc -w -funroll-loops -O2 -fno-inline -fipa-pta -msse2 -funsafe-math-optimizations -ftree-vectorizer-verbose=1 -fopt-info-optimized=logs/optOpt.txt -shared -fPIC singleThread.cpp

我遇到段错误。

fish: './a.out' terminated by signal SIGSEGV (Address boundary error)

关键是我不知道为什么会这样。我怀疑这些循环中使用的常量可能有问题。但我不认为这是相关的。如果我只是使用 -O0 优化编译这段代码,它就可以正常工作(因为我猜编译器不会矢量化某些东西)。

能否请您看一下下面的代码,并建议我应该检查哪个方向。 谢谢。

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <random>
#include <cstdio>
#include <set>
#include <fstream>
#include <cstdint>
#include <climits>

using namespace std;

const int STRING_HASH_SIZE = 32;

int convert(vector<string> &inputVector, const char **outputArray);

void printCollisions(const char **charArray, int size);

void printArray(const char **arrayToPrint, int size);

int getHashCode(const char *characters, unsigned long size);

string getRandomString();

void writeFileIfNeeded(vector<string> &vector, bool needToWrite);

vector<string> generateStringsVector(int size, bool isNeedToWriteFile);

/**
 * main method is present to test these native code.
 * to perform some external operation we should use another method.
 * @return
 */
int main() {

    /**
     * The constant represents number of strings that will be generated
     * in the string vector generation.
    */
    const int STRING_NUMBERS = 100000;

    vector<string> inputVector = generateStringsVector(STRING_NUMBERS, false);

#pragma pack 8
    const char *charArray[inputVector.size()];

    int hashResult = convert(inputVector, charArray);

    if (hashResult != 0) {
        return 0;
    }

    printCollisions(charArray, STRING_NUMBERS);
}

/**
 * Converts an input vector to char array.
 * Getting a hash of
 * Returns 0 if conversion from vector to array has been successfully performed.
 * @param  inputVector [ input array reference ]
 * @param outputArray [ a char array that would contain char sequences from vector ]
 * @return           [ hash sum (int)]
 */
int convert(vector<string> &inputVector, const char **outputArray) {
    int hashSum = 0;
#pragma loop(hint_parallel(8))
    for (int i = 0; i < inputVector.size(); i++) {
        outputArray[i] = inputVector[i].c_str();
    }

#pragma loop(hint_parallel(8))
    for (auto &i : inputVector) {
        hashSum += getHashCode(i.c_str(), i.length());
    }

    int stringHashSize = STRING_HASH_SIZE;
#pragma loop(hint_parallel(8))
    for (int i = 0; i < inputVector.size(); i++) {
        hashSum -= getHashCode(outputArray[i], stringHashSize);
    }

    if (hashSum != 0) {
        cout << "\nConversion isn't succeeded, hash = " << hashSum << endl;
    } else {
        cout << "\nConversion succeeded" << endl;
    }
    return hashSum;
}

/**
 * Prints count and percentage of collisions in array hash codes
 * @param charArray
 * @param size
 */
void printCollisions(const char **charArray, int size) {
    set<int> setOfHashes;
    int stringHashSize = STRING_HASH_SIZE;
#pragma loop(hint_parallel(8))
    for (int i = 0; i < size; i++) {
        setOfHashes.insert(getHashCode(charArray[i], stringHashSize));
    }
    unsigned long collisions = size - setOfHashes.size();
    cout << collisions << "/" << size << " " << 100.0 * collisions / size << "% of collisions";
}

/**
 * Prints input char array
 * @param arrayToPrint
 */
void printArray(const char **arrayToPrint, int size) {
    cout << "\nPrinted array size = " << size << endl;
    for (int i = 0; i < size; i++) {
        cout << arrayToPrint[i] << ":" << getHashCode(arrayToPrint[i], STRING_HASH_SIZE) << endl;
    }
}

/**
 *
 * @param characters
 * @return
 */
int getHashCode(const char *characters, unsigned long size) {
    int hash = 0;
#pragma loop(hint_parallel(8))
    for (int i = 0; i < size; i++) {
        hash = (31 + hash) * (characters[i]);
    }
    return hash;
}

/**
 * Get a random String from alphabetical char sequence.
 * @return a randomized string according to an alphabet.
 */
string getRandomString() {
    string str("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
    random_device rd;
    mt19937 generator(rd());
    shuffle(str.begin(), str.end(), generator);
    return str.substr(0, STRING_HASH_SIZE);
}

/**
 * Generates a vector with random strings
 * @param size - an int value that will be used as size of a generated vector
 * @return reference to generated vector.
 */
vector<string> generateStringsVector(int size, bool isNeedToWriteFile) {
    vector<string> charArray;
#pragma loop(hint_parallel(8))
    for (int i = 0; i < size; i++) {
        string str = getRandomString();
        charArray.push_back(str);
    }
    writeFileIfNeeded(charArray, isNeedToWriteFile);
    return charArray;
}

/**
 * Writes file with name according to vector size (e.g. 100000.csv)
 * if needToWrite is true
 * @param vector
 * @param needToWrite
 */
void writeFileIfNeeded(vector<string> &vector, bool needToWrite) {
    if (needToWrite) {
        ofstream csvFile;
        string filename = to_string(vector.size()) + ".csv";

        csvFile.open(filename, fstream::out);
        for (const auto &i : vector) {
            csvFile << i << "\n";
        }
        csvFile.close();
    }
}

最佳答案

导致段错误的原因是您编译代码的方式,而不是编译指示(编译指示对 gcc 没有任何影响,见下文):

gcc -w -funroll-loops -O2 -fno-inline -fipa-pta -msse2 -funsafe-math-optimizations -ftree-vectorizer-verbose=1 -fopt-info-optimized=logs/optOpt.txt -shared -fPIC singleThread.cpp

  • 通过使用-shared -fPIC,您正在创建一个DSO(动态共享对象)。如果您尝试执行此文件,您将得到一个无效的 PC(程序计数器)并且您的程序将立即崩溃。您必须编译您的代码 -shared -fPIC(如果您需要位置无关的可执行文件<,则使用-pie -fPIE/em>).
  • 此外,对于编译 C++ 代码,您通常应该使用 g++ 而不是 gcc
  • 给定的编译指示不应对您的代码产生任何影响,因为这些编译指示只能被 Microsoft Visual Studio 理解。将 -Wall 添加到您的编译选项,gcc 将向您显示相应的警告。
  • 在任何情况下,您都应该摆脱特定于供应商的 pragma,并改用 OpenMP 等标准化解决方案(使用 -fopenmp 编译)。这样,您离编写独立于编译器的代码又近了一步。
  • 至于并行循环,您应该确保不会遇到竞争条件或其他同步失败。例如,要计算总和,#pragma omp parallel for reduction(+: sum) 是您在 OpenMP 中的 friend (reference sheet)。

免责声明:我在 x86_64 (CentOS Linux) 上使用 gcc 7.3.0。

关于c++ - 添加#pragma loop 后出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50644261/

相关文章:

c++ - 结构内的卡尔曼滤波器无法对其进行初始化

python - 为什么单循环函数比双循环慢?

c - 二叉树顶 View 分割错误

c - 从字符串中提取子字符串时出现意外行为

c - 在另一个函数中修改数组 - 崩溃

c - 尝试使用 git_clone 函数导致段错误

c++ - 依赖模板可以使用 Visual Studio 编译,但使用 clang/gcc 失败

c++ - 在没有 'thread management' 的 C++ 中并发哈希表/哈希集?

c++ - 将父类(super class)传入/传出方法时如何防止自动向下转型

regex - golang 删除数组的一个维度