How to use the thread with the container C++

Viewed 245

If I want to edit each element of a vector, I can use for_each() to loop through the elements. The problem now is, how can I separate this task into two threads?

I've tried the way below, declaring a thread with for_each(), but I'm getting errors for that.

For example, I'd like to add 1 to each element of the vector. By using the threads, it seems like I'm missing something that the compiler does not like.

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

using namespace std;

int main()
{
    std::vector<int> nums;   //declare a vector
    nums.push_back(1);
    nums.push_back(2);
    nums.push_back(3);
    nums.push_back(4);     //push each element to the vector
    size_t i = (nums.size()/2);   //I want to separate the task into two thread 
    std::thread t1(std::for_each(nums.begin(),nums.begin()+i,[](int& num){
        num++;
    }));
    std::thread t2(std::for_each(nums.begin()+i,nums.end(),[](int& num){
        num++;
    }));
    
    t1.join();
    t2.join();

    return 0;
}

I'm getting these two errors:

Failed to specialize function template 'unknown-type std::invoke(_Callable &&) noexcept(<expr>)'

and

invoke': no matching overloaded function found

If I cannot do the threads in this way, what's the right way?

2 Answers

From C++17 onwards, you don't have to create your own threads in order to parallelise your code. Instead, you can pass the appropriate execution_policy to std::for_each:

std::for_each (std::execution::par_unseq, nums.begin (), nums.end (), [] (int& num) { num++; });

Since there are no data races in your code, this is safe.

Paul's got a better approach, but if you don't have C++17 available, and to explain what went wrong, in

std::thread t1(std::for_each(nums.begin(),nums.begin()+i,[](int& num){
    num++;
}));

the

std::for_each(nums.begin(),nums.begin()+i,[](int& num){
    num++;
})

is a function call that returns a value almost usable in the thread constructor, making the error message much harder to interpret than it otherwise could have been1. You didn't want to call this function. You wanted the function run in the thread, so you need to pass in the function. And that means you somehow need to provide the parameters to the function to the thread.

The easiest fix that I can see is to insert another lambda that calls for_each with the correct range

std::thread t1([i, &nums]()
               {
                   std::for_each(nums.begin(),
                                 nums.begin()+i,
                                 [](int& num)
                                 {
                                     num++;
                                 });
               });

1 Just ran a test with a few different compilers and I'm slightly wrong. The error message if you provide something like int func() that returns a type that clearly cannot be callable is just as messy. Nearly identical in fact.

Related