Reputation: 21
I'm a beginner in CPP and we have reached in class the subject of threading. I'm trying to play with it a bit and it seem not to work as I want it.
I want each thread to push the number of j inside the vector and then print the vector to the console.
It seems that all of them print the value '10' the last value that j holds after the end of the loop.
vector<int> foo(int x) {
vector<int> a;
a.push_back(x);
return a;
}
void print(vector<int> vec) {
for (int i = 0; i<int(vec.size()); i++)
cout << vec[i] <<endl;
}
void foo2(int x) {
vector<int> b;
thread thr([&] {b = foo(x); });
thr.join();
mtx1.lock();
print(b);
mtx1.unlock();
}
int main() {
vector<thread> th;
for (int j = 0; j < 10; j++)
th.emplace_back(([&] {foo2(j); }));
for (int j = 0; j < 10; j++)
th[j].join();
}
NOTE: I want that the vector of threads will go inside the function call a new thread that will push the number into the vector and then print.
The output I get is:
10
10
10
10
10
10
10
10
10
10
I'm aiming for:
0
1
2
3
4
5
6
7
8
9
Thanks for your help.
Upvotes: 2
Views: 84
Reputation: 118340
for (int j = 0; j < 10; j++)
th.emplace_back(([&] {foo2(j); }));
The lambda captures j
by reference (that's what [&]
means, after all), the lambda gets used to construct a new std::thread
, and this for
loop immediately iterates, incrementing j
.
But, if you were paying close attention, you would've noticed that j
is captured by reference, and C++ gives you no guarantees, whatsoever, that the new thread will read the value of j
, and call foo2()
, before the for
loop in the parent thread iterates and increments j
.
What happens here is that the for loop runs quickly enough so that it finishes before all the threads actually start running on their own, and all they see is the last value of j
(and not even that, since this specific j
goes out of scope and gets destroyed when this for
loop terminates, because it's declared local to the for
loop, which technically means that accessing j
makes demons fly out of your nose).
Solution: capture j
by value (that would be [=]
or [j]
), not reference.
P.S. And even after you do that, you have no guarantees whatsoever that all the values from 0 to 9 will be printed in order. It all depends upon the threads executing std::cout << ...
in the specific order, which, again, you have absolutely no guarantees about which thread will reach that statement in relationship to all other threads.
Upvotes: 4