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

时间:2016-09-18 11:57:15

标签: c++ multithreading c++11 thread-local

让我们从一段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实例结束。

2 个答案:

答案 0 :(得分:6)

这是一个语法问题:在这种情况下,a->i; 相同 A::i;,因为A::i静态成员及其地址不依赖于A的任何一个实例。

因为您使用的语法看起来像是取消引用A指针,所以不是。编译器看到它是静态成员并忽略指针并直接进入单个(在这种情况下为每个线程)static实例。整个thread_local业务实际上与此无关。

因此,当您在 lambda 中访问AA* 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'之外,它们是不同的。