I have a trouble with passing begin() and end() iterators of vector to the thread. I would like to understand the mechanism of threads and I trying to do something like this:
#include <iostream>
#include <numeric>
double accum(double *beg, double *end)
{
return std::accumulate(beg,end,0);
}
int main()
{
std::vector<double> v;
std::thread t1(accum, &v.begin(), &v.end());
t1.join();
return 0;
}
I know that thread copy arguments and stores only rvalues - so here we should pass some wrapped pointer but how can I do this? Please explain me. I have already tried using & or std:: ref().
CodePudding user response:
Remove std::thread
and make your code work without it. It should be either:
using iter = std::vector::const_iterator;
double accum( iter beg, iter end)
{
return std::accumulate(beg,end,0);
}
std::vector<double> v;
accum( v.begin(), v.end() );
Or if you insist to use double *
instead for some reason:
double accum(double *beg, double *end)
{
return std::accumulate(beg,end,0);
}
std::vector<double> v;
accum( v.data(), v.data() v.size() );
Now you can replace direct call with std::thread
in either case. Your problem is not with std::thread
, you just are trying to pass wrong arguments to your function.
CodePudding user response:
The ::begin()
and ::end()
functions of any container in the standard library are iterators to the beginning and end of the containers data. These are pointer-like constructs used for accessing the containers elements. The standard libraries functions are design to take these iterators directly (see the bottom for links to std::accumulate documentation).
Declaring a wrapper function such that std::thread
can call it it the right thinking as dealing with std::accumulate
template parameters explicitly (or any algorithm for that matter) can difficult and tricky to get right however, a typical function is not the desirable method. Instead what you want is a lambda that encapsulate the call to std::accumulate
.
Because you're using threads, I also used atomics so the accumulated result was thread safe on assignment.
Just remember to link with -ltbb
and -pthread
.
eg.
#include <atomic>
#include <iostream>
#include <numeric>
#include <thread>
#include <vector>
int main()
{
std::vector<double> v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // dummy data
auto result {0}; // actual result
std::atomic_ref<int> r { result }; // atomic reference to result
// Captures atomic ref
std::thread t1([&r](auto f, auto e, auto i) { r = std::accumulate(f, e, i); }
, v.begin(), v.end(), 0);
t1.join();
std::cout << r << '\n';
return 0;
}
Alternative
Alternatively you can use the parallel version of accumulate, std::reduce
with the std::execution policies but you'll need C 17. Don't forget to link with the same libraries as above.
#include <execution>
#include <iostream>
#include <numeric>
#include <vector>
namespace stdx = std::execution;
int main()
{
std::vector<double> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};
auto r = std::reduce(stdx::par, v.begin(), v.end(), 0);
std::cout << r << '\n';
return 0;
}