2014-12-17 3 views
1

Я не хороший программист на C++, но в настоящее время я использую некоторые функции C++ для очистки грязных частей моего кода на C. Компилятор g ++ жалуется на threads[i] = thread(split, i, sums[i], from, to, f, nThreads);. Пожалуйста, помогите мне найти проблему.std :: threads constructor аргумент error

// mjArray - просто тонкий класс, который нужно использовать вместо std :: vector, который слишком тяжел в моем случае.

#include <cstdio> 
#include <cmath> 
#include <ctime> 
#include <thread> 
using namespace std; 

template<typename T> 
class mjArray { 
private: 
    T* _array; 
    int _length; 

public: 
    mjArray(int length) { 
     _array = new T[length]; 
     _length = length; 
    } 

    mjArray(int length, T val) { 
     _array = new T[length]; 
     _length = length; 
     for (int i = 0; i < length; ++i) { 
      _array[i] = val; 
     } 
    } 

    ~mjArray() { 
     delete[] _array; 
    } 

    T& operator[](int i) { 
     return _array[i]; 
    } 

    int length() { 
     return _length; 
    } 
}; 

void split(int n, double& sum, int from, int to, double (*f)(double), int nThreads) { 
    for (int i = from + n; i <= to; i += nThreads) { 
     sum += f(i); 
    } 
} 

double sigma(int from, int to, double (*f)(double), int nThreads) { 
    double sum = 0.0; 
    mjArray<double> sums(nThreads, 0.0); 
    mjArray<thread> threads(nThreads); 
    for (int i = 0; i < nThreads; ++i) { 
     threads[i] = thread(split, i, sums[i], from, to, f, nThreads); 
    } 
    for (int i = 0; i < nThreads; ++i) { 
     threads[i].join(); 
     sum += sums[i]; 
    } 
    return sum; 
} 

double f(double x) { 
    return (4/(8 * x + 1) - 2/(8 * x + 4) - 1/(8 * x + 5) - 1/(8 * x + 6))/pow(16, x); 
} 

int main(void) { 
    for (int i = 1; i <= 4; ++i) { 
     time_t start = clock(); 
     double pi = sigma(0, 1000000, f, i); 
     time_t end = clock(); 
     printf("pi = %.10f; nThreads = %d; elapsed = %.3fs\n", pi, i, (double)(end - start)/CLOCKS_PER_SEC); 
    } 
    return 0; 
} 
+0

В чем проблема? Непонятно из вашего вопроса – justanothercoder

+1

Обратите внимание, что это плохая идея, чтобы смежные значения в массиве обновлялись разными потоками. Хотя это семантически правильно, вы создаете искусственное соперничество из-за необходимости синхронизировать линии кэша, т. Е. Вы получаете меньше параллелизма, чем вы надеялись. Вам было бы намного лучше поместить элементы массива в разные строки кэша или создать отдельные значения, например, путем их размещения (и, позднее, конечно, их освобождения), поскольку они с меньшей вероятностью будут находиться на та же линия кеша. –

+0

дубликат http://stackoverflow.com/q/21048906/981959 и http://stackoverflow.com/q/8299545/981959 –

ответ

5
#include <functional> 

threads[i] = thread(split, i, std::ref(sums[i]), from, to, f, nThreads); 
//       ~~~~~~~~^ 

Обоснование:

std::thread хранит сгнившие копии аргументов, передаваемых в его конструктор, которые затем std::move д для инициализации параметров объекта функтора работает в этом новом потоке. В случае ссылок это не выполняется, поскольку вы не можете инициализировать ссылку на константу lalue (это double& функция split ожидает) с xvalue (не говоря уже о том, что это совершенно другой экземпляр double, чем тот, который вы передали в конструктор thread's) ,

Решение заключается в использовании std::reference_wrapper<T> вернулся из вспомогательной функции std::ref что оборачивает вашу ссылку в Copyable объекта, который успешно переносит вашу ссылку на вновь созданный поток.

+1

Ваше решение работает точно так, как ожидалось! не могли бы вы немного объяснить мне, как это работает? – xiver77

+0

уверен, что в одно мгновение –

Смежные вопросы