“所有具有线程局部存储持续时间的非局部变量都作为线程启动的一部分进行初始化,在线程函数开始执行之前进行排序。” ( https://en.cppreference.com/w/cpp/language/initialization )
但是, cppreference 似乎没有提到这些变量实际上是由正在启动的线程还是由正在启动新线程的线程初始化的。
考虑以下示例:
(id.hpp)
#include<thread>
extern thread_local const std::thread::id this_thread_id;
(id.cpp)#include "id.hpp"
thread_local const std::thread::id this_thread_id = std::this_thread::get_id();
如果我访问 this_thread_id
从一个不是主线程的线程中,我会得到那个线程的 id 吗?如 this_thread_id
被初始化为“作为线程启动的一部分”,它也可能由原始调用线程初始化,因此 this_thread_id
会有不正确的值。我知道有一些设计模式可以完全避免这个问题,但这违背了这个问题的全部意义,所以我不想在这里使用它们。
最佳答案
作为本地线程,每个线程都会有一个拷贝,因此每个线程中都会有不同的值。
至于什么时候初始化:
is sequenced before the first statement of the initial function of a thread or is deferred. If it is deferred, the initialization associated with the entity for thread t is sequenced before the first non-initialization odr-use by t of any non-inline variable with thread storage duration defined in the same translation unit as the variable to be initialized
所以它在每个线程中被初始化,无论是在运行线程函数之前还是在使用之前。
我编写了一个测试:
#include <thread>
#include <iostream>
namespace m {
std::thread::id get_id () {
std::cout << "My get id called." << std::endl;
return std::this_thread::get_id();
}
}
thread_local const std::thread::id this_thread_id = m::get_id();
int main ()
{
std::cout << "Main: " << this_thread_id << std::endl;
std::thread th2 (
[&]{
uint64_t i {0};
std::cout << "Thread.int: " << i << std::endl;
std::cout << "Here it could be uninitialized." << std::endl;
std::cout << "Thread .2: " << this_thread_id << std::endl;
});
th2.join ();
std::cout << "End" << std::endl;
return 0;
}
这是输出:manuel@desktop:~/projects/soanswers/src (master)$ g++ ini.cc -o ini -std=c++2a -pthread && ./ini
Main: My get id called.
140064769697600
Thread.int: 0
Here it could be uninitialized.
Thread .2: My get id called.
140064769693440
End
所以它似乎在 g++
它在第一次使用时被初始化。即使您只访问它所在的内存。
关于c++ - thread_local 变量的实例是否保证由访问它们的线程初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65521829/