Mik*_*ine 16 c++ language-lawyer thread-local-storage c++11 stdthread
在 lambda 中捕获 thread_local:
#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();
}
Run Code Online (Sandbox Code Playgroud)
https://godbolt.org/z/zeocG5ohb
看起来如果我使用 a 的原始名称,thread_local那么执行 lambda 的线程上的值就是thread_local运行 lambda 的线程的版本。但是,一旦我获取对本地线程的引用或指针,它就会变成(指向)原始线程实例的指针。
这里有什么规则。我可以依赖这个分析吗?
Jan*_*tke 16
与本地对象类似static,本地thread_local(隐式static thread_local)对象在控制第一次通过其声明时被初始化。
您创建的线程永远不会执行main,只有主线程执行,因此您user在额外线程的生命周期开始之前进行访问。
std::thread([&]() {std::cout << "Hello " << referenceToUser.name << std::endl;}).join();
Run Code Online (Sandbox Code Playgroud)
我们正在捕获referenceToUser它指的是user主线程上的。这没关系。
std::thread([&]() {std::cout << "Hello " << user.name << std::endl;}).join();
Run Code Online (Sandbox Code Playgroud)
我们正在user额外线程的生命周期开始之前对其进行访问。这是未定义的行为。
std::thread([&user=user]() {std::cout << "Hello " << user.name << std::endl;}).join();
Run Code Online (Sandbox Code Playgroud)
我们再次user从主线程引用 ,这与第一种情况相同。
如果您user在 之外声明main,则将user在线程启动时初始化,而不是在main运行时初始化:
thread_local Person user{"mike"};
int main() {
// ...
Run Code Online (Sandbox Code Playgroud)
或者,user在 lambda 表达式内部声明。
注意:没有必要捕获thread_local对象。第二个例子可以是[] { ... }。