简体   繁体   中英

C++ thread with lambda function

I am learning C++ std thread with lambda function. In the following example, I don't know why the third argument (the lambda) for for_each has to use std::thread &t as its parameter.

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

int main()
{
    // vector container stores threads
    std::vector<std::thread> workers;
    for (int i = 0; i < 5; i++) {
        workers.push_back(std::thread([]() 
        {
            std::cout << "thread function\n";
        }));
    }
    std::cout << "main thread\n";

    std::for_each(workers.begin(), workers.end(), [](std::thread &t) 
    {
        t.join();
    });

    return 0;
}

With std::thread t , it gives the following compilation error:

In file included from /usr/include/c++/4.8.2/algorithm:62:0,
                 from foo.cc:6:
/usr/include/c++/4.8.2/bits/stl_algo.h: In instantiation of ‘_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<std::thread*, std::vector<std::thread> >; _Funct = main()::__lambda1]’:
foo.cc:20:3:   required from here
/usr/include/c++/4.8.2/bits/stl_algo.h:4417:14: error: use of deleted function ‘std::thread::thread(std::thread&)’
  __f(*__first);
              ^
In file included from foo.cc:2:0:
/usr/include/c++/4.8.2/thread:125:5: error: declared here
     thread(thread&) = delete;
     ^
foo.cc:18:64: error:   initializing argument 1 of ‘main()::__lambda1’
  std::for_each(workers.begin(), workers.end(), [](std::thread t) {

I also checked that if I replace std::thread with int in my example, using int t as the third argument for for_each also works.

std::for_each(workers.begin(), workers.end(), [](std::thread &t) 
{
    t.join();
});

can be translated to

for (auto it = workers.begin(), end = workers.end(); it != end; ++it)
{
    std::thread &t = *it; // take a reference to the element, this is fine
    t.join();
}

When you leave out the & and take the thread by value then you get

for (auto it = workers.begin(), end = workers.end(); it != end; ++it)
{
    std::thread t = *it; // make a copy of the element, boom
    t.join();
}

You make a copy, but std::thread can't be copied, so you get an error. For the manual loop you could "fix" that by using std::move like

for (auto it = workers.begin(), end = workers.end(); it != end; ++it)
{
    std::thread t = std::move(*it); // now we move into t
    t.join();
}

and you can get this same behavior in std::for_each by using std::make_move_iterator like

std::for_each(std::make_move_iterator(workers.begin()),
              std::make_move_iterator(workers.end()), 
              [](std::thread t) 
{
    t.join();
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM