添加#pragma循环后的Segfault

时间:2018-06-01 13:12:47

标签: 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'由信号SIGSEGV(地址边界错误)终止

关键是我不知道为什么会这样。我怀疑在这些循环中使用的常量可能是个问题。但我不认为这是相关的。如果我只是使用-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();
    }
}

1 个答案:

答案 0 :(得分:4)

导致细分错误的原因是您编译代码的方式而不是编译指示(无论如何都不会对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
  • 此外,要编译C ++代码,通常应使用g++代替gcc
  • 给定的编译指示不应对您的代码产生任何影响,因为这些只能由Microsoft Visual Studio理解。将-Wall添加到您的编译选项中,gcc将显示相应的警告。
  • 在任何情况下,您都应该摆脱特定于供应商的编译指示,并使用OpenMP等标准化解决方案(使用-fopenmp编译)。这样,您就可以更接近编写与编译器无关的代码了。
  • 对于并行化循环,您应该确保不会遇到竞争条件或其他同步失败。例如,要计算总和,#pragma omp parallel for reduction(+: sum)是您在OpenMP中的朋友(reference sheet)。

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