繁体   English   中英

使thread_local变量完全不稳定

[英]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_fenceasm volatile ("" : : : "memory"); std::atomic_thread_fence asm volatile ("" : : : "memory");

当同一点之后不同的线程可以继续执行时, 使用您描述的相同的技术来实现“持续窃取”。 他们明确不鼓励在Cilk计划中使用TLS。 相反,他们建议使用“hyperobjects” - Cilk的一个特殊功能,它替代TLS(并且还提供串行/确定性连接语义)。 另请参阅有关thread_local和parallelism的Cilk开发人员演示文稿

此外,当使用Fibers (相同的轻量级上下文切换)时,Windows提供FLS(光纤本地存储)作为TLS替换。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM