Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda inside loop

Tags:

c++

c++11

lambda

I have a lambda inside a for loop with the loop variable parameter in the lambda. When I run it, I expect the numbers 0-9 to be output. But since it is a lambda, the x doesn't get evaluated immediately.

    for( int x = 0; x < n; ++x)
    {
            vec.push_back(thread{[&x](){
                    m.lock();
                    cout << x << endl;
                    m.unlock();
            }});
    }

Output:

0
3
3
9

etc.

The solution for other languages would be to create a temporary variable,

    for( int x = 0; x < n; ++x)
    {
            int tmp = x;
            vec.push_back(thread{[&tmp](){
                    m.lock();
                    cout << tmp << endl;
                    m.unlock();
            }});
    }

but that doesn't seem to work.

see Threads receiving wrong parameters

Bonus:

In my search for an answer, I stumbled upon this question Generalizing C++11 Threads class to work with lambda which recommends not using a container that would invalidate the iterators. Why would that be/

like image 860
SaulBack Avatar asked Sep 17 '12 00:09

SaulBack


2 Answers

When you specify the capture, you can choose between capture by value and capture by reference. You have chosen to capture by reference. Capturing by reference means that the variable inside the lambda function is referring to the same object. The implication is that any changes to this variable will be shared and you also need to make sure that the referenced object stays around for the life-time of the lambda function.

You probably meant to capture by values. To do this, you can either replace the capture specification to become [=] or to become [x]. The latter makes sure that only x can be accessed while the former would allow other variables to be accessible.

BTW, I'd recommend not using lock() and unlock() explicitly but rather use one of the lock guards. With this, the body of your loop would look something like this:

vec.push_back(std::thread{[x](){
    std::lock_guard<std::mutex> kerberos(m);
    std::cout << x << "\n";
}});
like image 104
Dietmar Kühl Avatar answered Nov 07 '22 09:11

Dietmar Kühl


Capture the parameter by value instead of by reference if you want to make a copy:

vec.push_back(std::thread{[x](){
  m.lock();
  std::cout << x << std::endl;
  m.unlock();
}});

This will copy the value of x at the time the lambda object was created (not at the time the thread was started).

In my search for an answer, I stumbled upon this question Generalizing C++11 Threads class to work with lambda which recommends not using a container that would invalidate the iterators. Why would that be/

Because it's talking about a completely different implementation which directly uses the pthreads library. You're using std::thread, which is designed to work in C++.

like image 40
Nicol Bolas Avatar answered Nov 07 '22 09:11

Nicol Bolas