我正在开发一个使用用户级上下文切换(使用 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 部分的线程读取tli
属于线程 1 的值。
我试图找出一种方法来防止编译器缓存线程局部变量的地址,并且volatile
还不够深入。是否有任何技巧(最好是标准的,可能是特定于 GCC 的)来防止缓存线程局部变量的地址?