Почему я получаю ошибку сегмента при создании темы? - PullRequest
0 голосов
/ 09 октября 2019

Я не понимаю, почему у меня возникает ошибка сегментации при создании и запуске потоков здесь. Это происходит в строке t[j] = thread(getMax, A);, и я очень озадачен, почему это происходит. threadMax[] - это максимум каждой нити. getMax() возвращает максимальное значение массива.

#include <iostream>
#include <stdlib.h>
#include <sys/time.h>
#include <thread>
#define size 10
#define numThreads 10
using namespace std;

int threadMax[numThreads] = {0};
int num =0;

void getMax(double *A){
    num += 1;
    double max = A[0];
    double min = A[0];
    for (int i =0; i<size; i++){
        if(A[i] > max){
            max = A[i];
        }
    }
    threadMax[num] = max;
}

int main(){
    int max =0;
    double S,E;
    double *A = new double[size];
    srand(time(NULL));
    thread t[numThreads];
    //Assign random values to array
    for(int i = 0; i<size; i++){
        A[i] = (double(rand()%100));
    }
    //create Threads
    for(int j =0; j <numThreads; j++){
        cout << A[j] << "    " << j << "\n";
        t[j] = thread(getMax, A);
    }

    //join threads
    for(int i =0; i< numThreads; i++){
        t[i].join();
    }

    //Find Max from all threads
    for(int i =0; i < numThreads; i++){
        if(threadMax[i] > max){
            max = threadMax[i];
        }
    }

    cout <<max;

    delete [] A;

    return 0;
}

Ответы [ 2 ]

5 голосов
/ 09 октября 2019

Поведение этого кода не определено:

 void getMax(double *A){
        num += 1;
        double max = A[0];
        double min = A[0];
        for (int i =0; i<size; i++){
              if(A[i] > max){
                        max = A[i];
                }
        }
        threadMax[num] = max;
}

num += 1 может разрешить нескольким потокам пытаться изменить num одновременно. Хуже того, когда num читается в threadMax[num] = max;, потоки могут видеть значения num, измененные другими потоками во время их работы.

Вам необходимо назначить каждому потоку номер некоторым безопасным способом.

Вот три способа, которыми он может потерпеть неудачу:

  1. Два потока делают num += 1; в одно и то же время, и в результате num увеличивается только один раз.

  2. Каждый поток делает num += 1;, прежде чем любой поток делает threadMax[num] = max;. Все потоки перезаписывают одну и ту же запись в массиве. (Который, на самом деле, выходит за пределы!)

  3. Код падает, поскольку его поведение не определено.

1 голос
/ 09 октября 2019

Как уже говорили другие, ваша переменная num не защищена от состояния гонки внутри getMax(), что может привести к ее повреждению, в результате чего getMax() получит доступ к массиву threadMax[] за пределами.

Вы можете избежать этого, просто полностью избавившись от этой переменной num и передав вместо этого индекс массива в качестве входного параметра std::thread.

Попробуйте что-то еще подобное:

#include <iostream>
#include <vector>
#include <array>
#include <thread>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;

const size_t size = 10;
const size_t numThreads = 10;

double threadMax[numThreads] = {};

void getMax(int idx, double *A){
    threadMax[idx] = *max_element(A, A + size);
}

int main(){
    srand(time(nullptr));

    vector<double> A(size);
    array<thread, numThreads> t;

    //Assign random values to array
    generate_n(A.begin(), size, [](){ return double(rand() % 100); });
    /* or:
    for(double &d : A){
        d = double(rand() % 100);
    }
    */

    //create Threads
    for(int j = 0; j < numThreads; ++j){
        cout << A[j] << "    " << j << "\n";
        t[j] = thread(getMax, j, A.data());
    }

    //join threads
    for(thread &thd : t){
        thd.join();
    }

    //Find Max from all threads
    double max = *max_element(threadMax.begin(), threadMax.end());
    cout << max;

    return 0;
}
...