通过非线程局部对象访问的线程局部变量

Thread local variable accessed through non-thread local object

先来一段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 的线程本地副本,即使我从另一个线程的另一个线程本地对象访问它。这是预期的行为吗?因为它不可能使用 "referer" 从另一个线程获取信息,除非我传递一个指针或引用到我想读取的外部 thread_local 对象。

与 "referer" 我指的是管理或可以让你从它的线程访问它自己的 thread_local 变量的东西。但这是不可能的!!任何产生 thread_local 变量的表达式,无论来自谁(我做了不同的测试,即使使用访问函数),都以使用读取线程的 thread_local 实例结束。

这是一个语法问题:在这种情况下 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 Class member access [ expr.ref ]

1. A postfix expression followed by a dot . or an arrow ->, optionally followed by the keyword template (14.2), and then followed by an id-expression, is a postfix expression. The postfix expression before the dot or arrow is evaluated; 65 the result of that evaluation, together with the id-expression, determines the result of the entire postfix expression.

...

65) If the class member access expression is evaluated, the subexpression evaluation happens even if the result is unnecessary to determine the value of the entire postfix expression, for example if the id-expression denotes a static member.

(强调我的)

你传递了一个'A' porinter,但是我们应该知道'i'变量和'p_a'变量实际上不属于'A',那么是静态的,所以虽然你启动一个由'A'指针传递的线程,然后修改'i'变量,它是不同的,因为这个'i'不在'i'之外,它们是不同的。