Capturing a thread_local in a lambda:
#include <iostream>
#include <thread>
#include <string>
struct Person
{
std::string name;
};
int main()
{
thread_local Person user{"mike"};
Person& referenceToUser = user;
// Works fine - Prints "Hello mike"
std::thread([&]() {std::cout << "Hello " << referenceToUser.name << std::endl;}).join();
// Doesn't work - Prints "Hello"
std::thread([&]() {std::cout << "Hello " << user.name << std::endl;}).join();
// Works fine - Prints "Hello mike"
std::thread([&user=user]() {std::cout << "Hello " << user.name << std::endl;}).join();
}
https://godbolt.org/z/zeocG5ohb
It seems like if I use the original name of a thread_local
then its value on the thread which executes the lambda is the thread_local
version of the thread which is running the lambda. But as soon as I take a reference or pointer to the thread local it turns into (a pointer to) the originating threads instance.
What are the rules here. Can I rely on this analysis?
&
in the[&]
. Example 1 and 3 I'm capturing something which isn't thethread_local
. Example 2 still has an issue as discussed in the accepted answer though. – Urgauser
even though you specified&
. Instead you have a new thread local variable in your lambda that has never been initialized – Disenchantstd::thread
, which the lambda finds when it runs inside thestd::thread
. But it isn't "in the lambda", as that same exact lambda could be executed on the main thread and find the old thread local instance. – Lamoree