0

I'm new to std::threads and I'm trying to figure out what I'm doing wrong.

The idea is having a static function inside a DataUtils class that splits the program in 10 threads, every of which will calculate "a part" of a convolution between two vectors.

For some reason it seems that the compiler can't assign the right function to the thread, but the arguments are correct.

Here is my code (I am sure there is a more elegant way to do this...)

void threadconv (std::vector<double> const &f, std::vector<double> const &g, std::vector<double> &out, int start, int stop,int nf,int ng){

   
    for(auto i(start); i < stop; ++i) {
        int const jmn = (i >= ng - 1)? i - (ng - 1) : 0;
        int const jmx = (i <  nf - 1)? i            : nf - 1;
        for(auto j(jmn); j <= jmx; ++j) {
            out[i] += (f[j] * g[i - j]);
        }
    }
}

class DataUtils{
static std::vector<double> multiThreadedConvolution(std::vector<double> const &f, std::vector<double> const &g, int divide){
        int const nf = f.size();
        int const ng = g.size();
        int const n  = nf + ng - 1;
        int i=0;

        std::vector<double> out(n, double());

        std::thread t1 (threadconv,f,g,out,0,divide,nf,ng);i++;
        std::thread t2 (threadconv,f,g,out,divide*i,(divide*i)+divide,nf,ng);i++;
        std::thread t3 (threadconv,f,g,out,divide*i,(divide*i)+divide,nf,ng);i++;
        std::thread t4 (threadconv,f,g,out,divide*i,(divide*i)+divide, nf,ng);i++;
        std::thread t5 (threadconv,f,g,out,divide*i,(divide*i)+divide, nf,ng);i++;
        std::thread t6 (threadconv,f,g,out,divide*i,(divide*i)+divide, nf,ng);i++;
        std::thread t7 (threadconv,f,g,out,divide*i,(divide*i)+divide, nf,ng);i++;
        std::thread t8 (threadconv,f,g,out,divide*i,(divide*i)+divide, nf,ng);i++;
        std::thread t9 (threadconv,f,g,out,divide*i,(divide*i)+divide, nf,ng);i++;
        std::thread t10 (threadconv,f,g,out,divide*i,out.size(), nf,ng);

        t1.join();
         t2.join();
         t3.join();
         t4.join();
         t5.join();
         t6.join();
         t7.join();
         t8.join();
         t9.join();
         t10.join();
        return out;
    }

}

After trying to compile, this is the error message I receive:

/usr/include/c++/7/thread:240:2: error: no matching function for call to ‘std::thread::_Invoker<std::tuple<void (*)(const std::vector<double, std::allocator<double> >&, const std::vector<double, std::allocator<double> >&, std::vector<double, std::allocator<double> >&, int, int, int, int), std::vector<double, std::allocator<double> >, std::vector<double, std::allocator<double> >, std::vector<double, std::allocator<double> >, int, int, int, int> >::_M_invoke(std::thread::_Invoker<std::tuple<void (*)(const std::vector<double, std::allocator<double> >&, const std::vector<double, std::allocator<double> >&, std::vector<double, std::allocator<double> >&, int, int, int, int), std::vector<double, std::allocator<double> >, std::vector<double, std::allocator<double> >, std::vector<double, std::allocator<double> >, int, int, int, int> >::_Indices)’
  operator()()
  ^~~~~~~~
/usr/include/c++/7/thread:231:4: note: candidate: template<long unsigned int ..._Ind> decltype (std::__invoke((_S_declval<_Ind>)()...)) std::thread::_Invoker<_Tuple>::_M_invoke(std::_Index_tuple<_Ind ...>) [with long unsigned int ..._Ind = {_Ind ...}; _Tuple = std::tuple<void (*)(const std::vector<double, std::allocator<double> >&, const std::vector<double, std::allocator<double> >&, std::vector<double, std::allocator<double> >&, int, int, int, int), std::vector<double, std::allocator<double> >, std::vector<double, std::allocator<double> >, std::vector<double, std::allocator<double> >, int, int, int, int>]
    _M_invoke(_Index_tuple<_Ind...>)
    ^~~~~~~~~
/usr/include/c++/7/thread:231:4: note:   template argument deduction/substitution failed:
/usr/include/c++/7/thread: In substitution of ‘template<long unsigned int ..._Ind> decltype (std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<void (*)(const std::vector<double, std::allocator<double> >&, const std::vector<double, std::allocator<double> >&, std::vector<double, std::allocator<double> >&, int, int, int, int), std::vector<double, std::allocator<double> >, std::vector<double, std::allocator<double> >, std::vector<double, std::allocator<double> >, int, int, int, int> >::_M_invoke<_Ind ...>(std::_Index_tuple<_Ind1 ...>) [with long unsigned int ..._Ind = {0, 1, 2, 3, 4, 5, 6, 7}]’:
/usr/include/c++/7/thread:240:2:   required from ‘struct std::thread::_Invoker<std::tuple<void (*)(const std::vector<double, std::allocator<double> >&, const std::vector<double, std::allocator<double> >&, std::vector<double, std::allocator<double> >&, int, int, int, int), std::vector<double, std::allocator<double> >, std::vector<double, std::allocator<double> >, std::vector<double, std::allocator<double> >, int, int, int, int> >’
/usr/include/c++/7/thread:127:22:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(const std::vector<double>&, const std::vector<double>&, std::vector<double>&, int, int, int, int); _Args = {const std::vector<double, std::allocator<double> >&, const std::vector<double, std::allocator<double> >&, std::vector<double, std::allocator<double> >&, int, int&, const int&, const int&}]’
Barsaas
  • 5
  • 6
  • `std::ref(out)` – Ben Voigt May 20 '21 at 17:15
  • Could you please clarify where this has to be put, and why? thanks – Barsaas May 20 '21 at 17:17
  • `std::thread` constructor makes a copy of every parameter you pass it. `std::reference_wrapper` can be copied and still converts to a reference to the same original object. Otherwise `invoke` tries to pass the copied object to `threadconv` and can't bind the non-const reference to the temporary copy. – Ben Voigt May 20 '21 at 17:19
  • 1
    @NateEldredge I haven't looked too thoroughly but it looks like each thread writes to its own range in the vector. That's safe. – Kevin May 20 '21 at 17:19
  • 1
    @NateEldredge: I first thought that too, but each thread writes to a mutually-exclusive subrange so there's no problem. – Ben Voigt May 20 '21 at 17:19
  • 1
    Does this answer your question? [std::thread pass by reference calls copy constructor](https://stackoverflow.com/questions/21048906/stdthread-pass-by-reference-calls-copy-constructor) – Kevin May 20 '21 at 17:23

0 Answers0