让我们从一段code (Coliru)开始:
#include <iostream>
#include <thread>
using namespace std;
struct A
{
thread_local static A* p_a;
thread_local static int i;
};
thread_local int A::i;
thread_local A* A::p_a;
int main( )
{
A::p_a = new A;
auto lambda = [](A* a)
{
a->i = 1; // Prints 1 (below, of course)
std::cout << a->i << std::endl;
};
std::thread t(std::bind(lambda, A::p_a));
t.join();
// Prints 0 (it hasn't been modified)
std::cout << A::p_a->i << std::endl;
return 0;
}
正如大家所看到的,第二个线程修改了A::i
的线程本地副本,即使我从另一个线程的另一个线程本地对象访问它。这是预期的行为吗?因为除非我将指针或引用传递给我想要读取的外部thread_local对象,否则无法使用“referer”从另一个线程获取信息。
使用“referer”我引用一些管理或可以让你从其线程访问自己的thread_local变量的东西。但那是不可能的!任何产生thread_local变量的表达式,无论是谁(我已经完成了不同的测试,甚至是访问器函数),都使用读取线程的thread_local实例结束。
答案 0 :(得分:6)
这是一个语法问题:在这种情况下,a->i;
相同 到A::i;
,因为A::i
是静态成员及其地址不依赖于A
的任何一个实例。
因为您使用的语法看起来像是取消引用A
指针,所以不是。编译器看到它是静态成员并忽略指针并直接进入单个(在这种情况下为每个线程)static
实例。整个thread_local
业务实际上与此无关。
因此,当您在 lambda 中访问A
到A* a
的静态成员时,编译器会忽略地址你提供了A::i
而不管(获得自己的thread_local
版本)。
struct A
{
static int i;
};
A* a = new A;
a->i; // identical to A::i (because i is static)
这是 C ++ 14标准:
中提到的标准语法5.2.5 类成员访问权限 [ expr.ref ]
1。后缀表达式后跟一个点。或箭头 - &gt;,可选地后跟关键字模板(14.2), 然后是一个id-expression,是一个后缀表达式。点或箭头前的后缀表达式 被评估; 65 评估的结果与id-expression一起确定了结果 整个后缀表达式。
...
65) 如果计算了类成员访问表达式,即使结果不必要,也会发生子表达式求值 确定整个后缀表达式的值,例如 如果id-expression表示静态成员 。
(强调我的)
答案 1 :(得分:0)
你通过了一个'A'的porinter,但我们应该知道'i'变量和'p_a'变量实际上不属于'A',然后是静态的,所以尽管你开始了一个'A'指针传递的线程,然后修改'i'变量,它是不同的,因为'i'不在'i'之外,它们是不同的。