从上下文切换谈thread_local工作原理

从上下文切换谈thread_local工作原理

thread_local是什么

熟悉多线程编程的小伙伴一定对thread_local不陌生,thread_local 是 C++11 引入的一种存储类说明符,用于定义每个线程都有其独立实例的变量。每个线程对这些变量有自己的副本,而不共享其他线程的副本。这在多线程编程中非常有用,确保线程之间的数据隔离,防止数据竞争。

但是thread_local的表现又很奇怪,你说它是全局变量吧,但它又被每个线程私有,比如下面这个例子:

#include <iostream>
#include <thread>
#include <stdio.h>

// 定义一个 thread_local 变量
thread_local int local_var = 0;

void thread_function(int id) {
    local_var = id;
    printf("%x\n", &local_var);
}

int main() {
    std::thread t1(thread_function, 1);
    std::thread t2(thread_function, 2);

    t1.join();
    t2.join();

    return 0;
}

输出:

image-20240604141151341

地址不同,说明两个线程里的local_var变量不是同一个。

但是你说它是局部变量吧,它的生命周期又很长,thread_local 变量的生命周期从线程创建时开始,到线程结束时结束。

其实抽象出它的具体含义就是:

每个线程独立实例: 每个线程对 thread_local 变量都有自己的独立副本,不会与其他线程的副本共享。

生命周期: thread_local 变量的生命周期从线程创建时开始,到线程结束时结束。

那么问题来了,每个线程都有自己的独立副本,在访问的时候又互不影响,这个是怎么实现的呢?这就引出了上下文切换这个概念。

上下文切换

我们先看一下最开始的thread_function对应的汇编代码:

image-20240604143232421
image-20240604143356925

寄存器fs记录了当前正在运行的线程所有的thread_local变量所在内存块的首地址。不同的线程,它的上下文也是不同的,所以寄存器fs的值也是不同的;这样就非常巧妙的通过线程的上下文切换区分了不同线程对应的thread_local;

如图:

image-20240604143849664

假设现在线程1正在执行,操作系统会创建线程1的上下文,上下文一般是指当前寄存器的值,他们包含了当前程序运行的状态,比如栈指针esp,程序计数器eip,在此例中也包含fs,fs记录了当前线程栈上的thread_local变量的起始地址。

同理我们再创建另一个线程2:

image-20240604145238079

线程1和线程2对应着程序运行栈上的不同区域,因此他们的fs寄存器的值也是不同的。所以当发生线程上下文切换的时候,操作系统会恢复将要运行的线程的上下文(寄存器状态)。这样每个线程也就能自然通过fs对应到它的thread_local变量。

总结

本篇博文先是介绍了thread_local的特性:

  • 每个线程独立实例: 每个线程对 thread_local 变量都有自己的独立副本,不会与其他线程的副本共享。

  • 生命周期: thread_local 变量的生命周期从线程创建时开始,到线程结束时结束。

然后通过上下文切换的概念介绍了实现的方法。有关更多上下文切换的内容,可参照《CPU眼中的C++》5.8节。

refer

《CPU眼中的C++》

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王行知

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值