通过非线程局部对象访问的线程局部变量
Thread local variable accessed through non-thread local object
让我们从一段代码(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 类成员访问 ( expr。ref ]
1。一个后缀表达式后面跟一个点。或者一个箭头->,可选后跟关键字template (14.2),然后跟一个id表达式,是一个后缀表达式。点或箭头前的后缀表达式评估;65该求值的结果与id-表达式一起决定整个后缀表达式
…
65)如果对类成员访问表达式求值,则即使结果是不必要的,也会对子表达式求值确定整个后缀表达式的值,例如,如果id-expression表示静态成员,则使用。
(强调我的)
你传递了一个'A'指针,但我们应该知道'i'变量和'p_a'变量实际上不属于'A',然后是静态的,所以虽然你启动了一个线程,通过'A'指针传递,然后修改'i'变量,它是不同的,因为这个'i'不在'i'之外,它们是不同的
- 最佳做法是从另一个线程访问 qml 中的Q_PROPERTY
- 线程消息传递或更好:在"大师班"中访问其他班级的成员
- C++:在多个线程中访问同一数组/向量的不同单元格是否会产生数据竞赛?
- 线程时访问静态映射时出现隔离错误
- 是否需要 mutex() 来安全地同时访问具有 2 个线程的数组的不同元素?
- 提供对不同类型的数据(建议、代码审查)的线程安全访问的类
- 从子线程访问指针
- 对C++中的队列进行多线程访问
- 对全局变量的多线程访问:我应该使用互斥锁吗?
- cuda:多个线程访问同一个全局变量
- 如何进行线程安全shared_ptr修改和访问?
- 如果迭代器的迭代器永远不会无效,则是STD :: MAP访问线程安全
- 如何在不将类数据成员作为参数传递的情况下访问线程中的类数据成员
- 在 C++ 中包含和访问线程全局变量
- QVector预先分配了访问线程安全性
- 使对unsigned char的访问线程安全(原子)
- 在 OpenMP 中访问线程的专用内存
- 访问线程中的vector.front()会导致运行时错误
- 访问线程(MFC)中的主对话框变量
- 从主循环windows访问线程变量