thread_local 线程内的变量不一致
thread_local variable not consistent within a thread
我在文件中有一个变量 tracker.hpp:
namespace TRIALS
{
static thread_local int a = -1;
}
我在 ema.hpp/ema.cpp
文件中还有一个名为 EMP 的文件 class
namespace Algo
{
class EMP
{
public:
void Sample();
};
}
namespace Algo
{
void EMP::Sample()
{
std::cout << "model " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;
}
}
然后我的主文件我有
auto model = Algo::EMP();
void Simulate(const int a)
{
TRIALS::a = a;
model.Sample()
std::cout << "worker " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;
}
int main()
{
std::cout << &TRIALS::a << std::endl;
const int nthreads = 1;
std::cout << "main " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;
std::vector<std::thread> threads;
for(int i=0; i<nthreads; ++i)
{
threads.emplace_back(&Simulate, i);
}
for(auto &thread : threads)
{
thread.join();
}
std::cout << "main " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;
return 0;
}
我只是 运行 一个用于调试的线程,但这是输出:
0x7f9540b621d8
main 140279012532800 0x7f9540b621d8 -1(符合预期)
model 140278985606912 0x7f953f1b469c -1(这不应该是0吗??)
工人 140278985606912 0x7f953f1b4698 0(如预期)
main 140279012532800 0x7f9540b621d8 -1(符合预期)
我的印象是每个线程都有自己的 TRIALS::a 本地副本。模型中的 a 正确地增加了,但是当它 returns 来自同一线程中的函数时,该值仍然为 0。我正在打印线程 ID 和 a 的地址,这是一个很好的衡量标准,我看到那里尽管总共只有两个线程,但实际上是 TRIALS::a 的 3 个不同版本。
作为加分题,static thread_local int a
和thread_local int a
有什么区别?
在您的示例中,static
使 thread_local
对象使用内部链接,以便每个翻译单元(.cpp 文件)都有自己的变量副本。
The thread_local
keyword is only allowed for objects declared at namespace scope, objects declared at block scope, and static data members. It indicates that the object has thread storage duration. It can be combined with static
or extern
to specify internal or external linkage (except for static data members which always have external linkage), respectively, but that additional static doesn't affect the storage duration.
即您可能希望删除 static
关键字,这样您在整个应用程序中就只有该对象的一个副本。在头文件中做:
namespace TRIALS {
extern thread_local int a;
}
并且在 .cpp
之一中:
thread_local int TRIALS::a = -1;
在 C++17 中,您可以创建变量 inline
以避免必须在 .cpp
:
中提供其定义
namespace TRIALS {
inline thread_local int a = -1;
}
我在文件中有一个变量 tracker.hpp:
namespace TRIALS
{
static thread_local int a = -1;
}
我在 ema.hpp/ema.cpp
文件中还有一个名为 EMP 的文件 classnamespace Algo
{
class EMP
{
public:
void Sample();
};
}
namespace Algo
{
void EMP::Sample()
{
std::cout << "model " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;
}
}
然后我的主文件我有
auto model = Algo::EMP();
void Simulate(const int a)
{
TRIALS::a = a;
model.Sample()
std::cout << "worker " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;
}
int main()
{
std::cout << &TRIALS::a << std::endl;
const int nthreads = 1;
std::cout << "main " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;
std::vector<std::thread> threads;
for(int i=0; i<nthreads; ++i)
{
threads.emplace_back(&Simulate, i);
}
for(auto &thread : threads)
{
thread.join();
}
std::cout << "main " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;
return 0;
}
我只是 运行 一个用于调试的线程,但这是输出:
0x7f9540b621d8
main 140279012532800 0x7f9540b621d8 -1(符合预期)
model 140278985606912 0x7f953f1b469c -1(这不应该是0吗??)
工人 140278985606912 0x7f953f1b4698 0(如预期)
main 140279012532800 0x7f9540b621d8 -1(符合预期)
我的印象是每个线程都有自己的 TRIALS::a 本地副本。模型中的 a 正确地增加了,但是当它 returns 来自同一线程中的函数时,该值仍然为 0。我正在打印线程 ID 和 a 的地址,这是一个很好的衡量标准,我看到那里尽管总共只有两个线程,但实际上是 TRIALS::a 的 3 个不同版本。
作为加分题,static thread_local int a
和thread_local int a
有什么区别?
在您的示例中,static
使 thread_local
对象使用内部链接,以便每个翻译单元(.cpp 文件)都有自己的变量副本。
The
thread_local
keyword is only allowed for objects declared at namespace scope, objects declared at block scope, and static data members. It indicates that the object has thread storage duration. It can be combined withstatic
orextern
to specify internal or external linkage (except for static data members which always have external linkage), respectively, but that additional static doesn't affect the storage duration.
即您可能希望删除 static
关键字,这样您在整个应用程序中就只有该对象的一个副本。在头文件中做:
namespace TRIALS {
extern thread_local int a;
}
并且在 .cpp
之一中:
thread_local int TRIALS::a = -1;
在 C++17 中,您可以创建变量 inline
以避免必须在 .cpp
:
namespace TRIALS {
inline thread_local int a = -1;
}