0

I'm currently trying to make my first steps in writing multi-threaded code in CPP and I'm getting a error message that I don't understand at all....

Consider the two functions:

void add_vector(std::vector<int> & vec, int & store){
    store = std::accumulate(vec.begin(), vec.end(), 0);
}

int parallel_matrix_sum(std::vector<std::vector<int>> const & mat){
    std::vector<std::thread> threads;
    std::vector<int> tmp(l); 
    for (int k =0; k<l; k++){
        threads.push_back(std::thread(add_vector, std::cref(mat[k]), std::ref(tmp[k])));
    }

    for(auto && thread: threads){
        thread.join();
    }

    return std::accumulate(tmp.begin(), tmp.end(), 0);
}

The error I get is

error: attempt to use a deleted function
.
.
.
in instantiation of function template specialization 'std::thread::thread<void (&)(std::vector<int> &, int &), std::reference_wrapper<const std::vector<int>>, std::reference_wrapper<int>, void>' requested here
        threads.push_back(std::thread(add_vector, std::cref(mat[k]), std::ref(tmp[k])));
                          ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/type_traits:1916:5: note: '~__nat' has been explicitly marked deleted here
    ~__nat() = delete;

Upon googling this issue, all the information points to the fact that std::thread needs to copy the arguments, which cannot be done for references.. The suggested solution seems to be to wrap the arguments in a std::ref call. I am already doing this and it is still not working. Does anybody have some suggestions?

  • 1
    Maybe replace `std::cref` with `std::ref` as your references are not `const`? Actually `add_vector` expects a *non const* reference but you are passong a *const* reference! – Galik Feb 23 '22 at 20:04
  • 4
    Or change `std::vector & vec` to `const std::vector & vec` since there doesn't seem to be any need to modify `vec` in `add_vector`. – user4581301 Feb 23 '22 at 20:08
  • Maybe it doesn't have anything to do with the arguments being references? Have you tried extracting a [mcve] to further your understanding of the issue? As a new user here, please also take the [tour] and read [ask]. – Ulrich Eckhardt Feb 23 '22 at 21:23

1 Answers1

0

I did some playing. I got this to work:

#include <iostream>
#include <thread>
#include <vector>

void add_vector(const int & a, const int & b, int & c) {
    c = a + b;
}   

int main() {
    std::vector<std::thread> threads;
    int a = 5;
    int b = 10;
    int c = 0;

    std::cout << "start threads.\n";

    threads.push_back(std::thread(add_vector, a, b, std::ref(c) ));

    std::cout << "Join.\n";
    for (std::thread &thread: threads) {
        thread.join();
    }

    std::cout << "Done. c == " << c << "\n";
}

This is with g++ using --std=c++17.

I updated this with info from Innocent Bystander. Passing by reference can work if you wrap in std::ref() as shown.

I'm going to try a fresh example with vectors.

#include <iostream>
#include <thread>
#include <vector>

void add_vector(const std::vector<int> & vec, int &result) {
    result = 0;
    for (const int &value: vec) {
        result += value;
    }
}   

int main() {
    std::vector<std::thread> threads;
    std::vector<int> values;
    std::vector<int> results;

    values.push_back(10);
    values.push_back(15);
    results.push_back(0);

    std::cout << "start threads.\n";

    threads.push_back(std::thread(add_vector, values, std::ref(results[0]) )); 

    std::cout << "Join.\n";
    for (std::thread &thread: threads) {
        thread.join();
    }

    std::cout << "Done. c == " << results[0] << "\n";
}

This above with vector works. I didn't wrap the first args. I did wrap the final one.

The end answer: take a look at the very first argument to your method. It isn't listed as const.

Joseph Larson
  • 8,530
  • 1
  • 19
  • 36