![](/img/trans.png)
[英]Are instances of thread_local variables guaranteed to be initialised by the thread that accesses them?
[英]Making thread_local variables fully volatile
我正在使用一个使用用户级上下文切换的运行时库(使用Boost :: Context),并且在使用thread_level
变量时遇到问题。 考虑以下(简化)代码:
thread_local int* volatile tli;
int main()
{
tli = new int(1); // part 1, done by thread 1
UserLevelContextSwitch();
int li = *tli; // part 2, done by thread 2
cout << li;
}
由于对thread_local
变量有两次访问,因此编译器将main函数转换为沿着这些行的某些内容(与程序集相反):
register int** ptli = &tli; // cache address of thread_local variable
*ptli = new int(1);
UserLevelContextSwitch();
int li = **ptli;
cout << li;
这似乎是一种合法的优化,因为volatile tli
的值不会缓存在寄存器中。 但是, volatile tli
的地址实际上是缓存的,而不是从第2部分的内存中读取。
这就是问题:在用户级上下文切换之后,执行第1部分的线程会转到其他位置。 然后,第2部分由其他线程获取,该线程获得先前的堆栈和寄存器状态。 但是现在执行第2部分的线程读取属于线程1的tli
的值。
我试图找出一种方法来阻止编译器缓存线程局部变量的地址 ,而volatile
也不够深入。 是否有任何技巧(最好是标准的,可能是GCC特定的)来阻止线程局部变量地址的缓存?
无法将用户级上下文切换与TLS配对。 即使使用原子和完整的内存栅栏,缓存地址似乎也是合法的优化,因为thread_local变量是文件范围的静态变量,它不能像编译器所假设的那样移动。 (但是,也许一些编译器仍然可以对编译器内存障碍敏感,比如std::atomic_thread_fence
和asm volatile ("" : : : "memory");
std::atomic_thread_fence
asm volatile ("" : : : "memory");
)
当同一点之后不同的线程可以继续执行时, cilk-plus使用与您描述的相同的技术来实现“持续窃取”。 他们明确不鼓励在Cilk计划中使用TLS。 相反,他们建议使用“hyperobjects” - Cilk的一个特殊功能,它替代TLS(并且还提供串行/确定性连接语义)。 另请参阅有关thread_local
和parallelism的Cilk开发人员演示文稿 。
此外,当使用Fibers (相同的轻量级上下文切换)时,Windows提供FLS(光纤本地存储)作为TLS替换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.