Reputation: 317
I am currently developing a multi-threaded server (with c++14) and I am facing kind of a strange problem, let me explain:
So here I am just creating nb_threads threads with a lambda expression and putting them in a forward_list:
unsigned nb_threads = 4;
std::forward_list<std::thread> threads;
for (unsigned i = 0; i < nb_threads; ++i)
threads.emplace_front(std::thread(
[i, this]()
{
std::cout << "Thread " << i + 1 << " launched!" << std::endl;
}));
This gives me this result on the stdout (which is correct):
Thread 2 launched!
Thread 3 launched!
Thread 4 launched!
Thread 1 launched!
Now let's just change [i, this] by [&] in the lambda expression:
for (unsigned i = 0; i < nb_threads; ++i)
threads.emplace_front(std::thread(
[&]()
{
std::cout << "Thread " << i + 1 << " launched!" << std::endl;
}));
This now gives me this result on the stdout (which is really mystic!):
Thread 2 launched!
Thread 1 launched!
Thread 1 launched!
Thread 1 launched!
So my question is What is happening ? Why can't I change for [&] ?
Upvotes: 3
Views: 372
Reputation: 15534
What is happening here when capturing i
by reference is a data race. When capturing by reference, each lambda will get a reference to the same memory location as the variable captured by reference.
Basically what is going on is that the main thread is writing to i
while the spawned threads are trying to read from the same variable, without synchronization.
Performing reads and writes to the same memory location concurrently without synchronization will cause a data race and exhibit nondeterministic behaviour.
Upvotes: 3
Reputation: 8661
This is no more "mystic" than the difference between
void thread_body (int i) {}
and
void thread_body (int &i) {}
In the first case the current value of the argument is passed to the thread and i won't change unless the function itself modifies it.
In the second you pass a reference to some external variable that is likely to change anytime, outside the function's control.
The only mystic thing here is the bloody awful C++ syntax, but since you're writing a multitasking C++14 server, you'll soon get used to it.
Upvotes: 3
Reputation: 182827
As the value of i
changes, the value of references to i
changes with it. Since you have no synchronization, such changes are unpredictable. Here, you clearly want to capture i
by value.
Upvotes: 3