当前位置: 首页 > 知识库问答 >
问题:

使thread_local变量完全可变

孔光赫
2023-03-14

我正在开发一个使用用户级上下文切换(使用Boost::Context)的运行时库,在使用< code>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;

这似乎是一种合法的优化,因为易失性 tli 的值没有缓存在寄存器中。但是易失性 tli 的地址实际上是缓存的,而不是从第 2 部分的内存中读取的。

这就是问题所在:在用户级上下文切换之后,执行第1部分的线程将转到其他地方。第2部分随后由其他线程获取,该线程获取先前的堆栈和寄存器状态。但是现在执行第2部分的线程读取属于线程1的tli的值。

我试图找出一种方法来防止编译器缓存线程局部变量的地址,而易失性不够深入。是否有任何技巧(最好是标准的,可能是特定于 GCC 的)来防止线程局部变量地址的缓存?

共有1个答案

长孙嘉
2023-03-14

无法将用户级上下文开关与TLS配对。即使使用原子和全内存Geofence,缓存地址似乎也是合理的优化,因为thread_local变量是文件范围的静态变量,不能像编译器假设的那样移动。(不过,也许有些编译器仍然对编译器内存障碍敏感,比如std::atomic_thread_fenceasm-volatile(“”::“memory”)

当不同的线程可以在同步点之后继续执行时,cilk-plus使用与您描述的相同的技术来实现“延续窃取”。并且它们明确不鼓励在Cilk程序中使用TLS。相反,他们推荐使用“超对象”Cilk的一个特殊特性,它取代了TLS(还提供了串行/确定性连接语义)。另请参见Cilk开发人员关于< code>thread_local和并行性的演示文稿。

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

 类似资料:
  • 如果你要多于一个函数共用一个简单的变量,简单的处理方法就是把这个变量在所有函数中定义为global全局变量。在命令行做同样的事情,如果你要工作空间访问上述变量。这个全局变量的定义必须出现在变量被应用于一个函数之前。虽然不是要求,但全局变量也最好以大写字母开头,这样可以同其他变量区别出来。举个例子,做一个以falling.m命名的M-文件。 function h = falling(t) globa

  • ThinkCMF封装了前台模板开发时常用的一些变量,这些变量是全局的,你在前台模板任何时候都能直接调用: {$site_name} /站点名称 {$site_host} /站点域名 {$site_root} /安装目录 {$site_icp} /

  • swoole内置了几个全局变量供程序内使用。一般不要自行创建全局变量。 SwooleG 超全局本地内存变量,此变量在swoole_init时就初始化好了。存储了一些全局的信息。但不是共享内存的。当创建子进程后再修改其中的字段,其他进程是感知不到的 SwooleG.main_reactor,全局事件循环 SwooleG.lock,全局锁 SwooleG.memory_pool,全局共享内存池 Swo

  • 全局变量 PHP中在函数、类之外直接定义的变量可以在函数、类成员方法中通过global关键词引入使用,这些变量称为:全局变量。 这些直接在PHP中定义的变量(包括include、require文件中的)相对于函数、类方法而言它们是全局变量,但是对自身执行域zend_execute_data而言它们是普通的局部变量,自身执行时它们与普通变量的读写方式完全相同。 function test() {

  • 问题内容: 我如何在for循环中创建变量变量? 这是循环: 在此循环中,我想为每次传递创建一个$ seat变量,但必须像这样递增。第一次通过应该是,下次通过:等等。 所以最后应该是: 等等。 因此$ _POST的变量和内容应该是动态的。 问题答案: 首先,除非缺少某些内容,否则我将为此使用数组。具有像变量,等趋于具有少得多的效用和是更为繁琐比使用的阵列。 话虽这么说,使用以下语法: 最后,PHP具

  • 变量绑定默认是不可变的,但加上 mut 修饰语后变量就可以改变。 fn main() { let _immutable_binding = 1; let mut mutable_binding = 1; println!("Before mutation: {}", mutable_binding); // 正确代码 mutable_binding += 1

  • 主要内容:局部变量,全局变量,局部变量和全局变量的综合示例在《 C语言形参和实参的区别》中提到,形参变量要等到函数被调用时才分配内存,调用结束后立即释放内存。这说明形参变量的作用域非常有限,只能在函数内部使用,离开该函数就无效了。 所谓 作用域( Scope ) ,就是变量的有效范围。 不仅对于形参变量,C语言中所有的变量都有自己的作用域。决定变量作用域的是变量的定义位置。 局部变量 定义在函数内部的变量称为 局部变量(Local Variable) ,

  • 问题内容: 我想定义一个常量,该常量应该在包的所有子模块中可用。我以为最好的地方在根包的文件中。但是我不知道该怎么做。假设我有几个子包,每个子包都有几个模块。如何从这些模块访问该变量? 当然,如果这是完全错误的,并且有更好的替代方法,我想知道。 问题答案: 您应该能够将它们放入。这一直都在做。 : : 然后,导入mymodule: 不过,如果您确实有常量,则将它们放入单独的模块(constants