深入理解thread_local

本文探讨了线程局部存储thread_local的概念,其在C++中的使用,以及在实际项目中可能遇到的风险,如内存分配、接口调用、跨模块调用和资源管理问题。作者建议开发者理解和合理利用thread_local以避免潜在问题。
摘要由CSDN通过智能技术生成

前言

近期线程局部存储thread_local的应用上,暴露出了不少问题,本文从概念到典型的案例分析,可以加深开发人员对thread_local的理解,有助于规避同类问题的发生。

线程局部存储

在Linux中有一种线程局部存储方法,就是使用关键字__thread来定义变量。__thread是GCC内置的线程局部存储设施(Thread-Local Storage),凡是带有__thread的变量,每个线程都拥有该变量的一份拷贝,且互不干扰。线程局部存储中的变量将一直存在,直至线程终止,当线程终止时会自动释放这一存储。__thread并不是所有数据类型都可以使用的,因为其只支持POD类型,不支持class类型——其不能自动调用构造函数和析构函数。同时__thread可以用于修饰全局变量、函数内的静态变量,但是不能用于修饰函数的局部变量或者class的普通成员变量。

thread_local是C++11引入的新特性,是一个关键字,用于修饰变量(thread_local关键字和static、extern关键字在使用上是不冲突的),告诉线程对此关键词修饰的数据进行本地存储。

thread_local的使用

thread_local主要是用来修饰变量,修饰变量的种类有以下四种

  • 1)全局变量
  • 2)局部变量
  • 3)类对象
  • 4)类成员变量

根据各个模块使用的情况,可以大致分为以下风险点。

1.线程大量的申请与释放可能引起不合适的接口调用

报盘插件中维护了线程局部变量“消息写入封装对象”,由于新创建线程会导致重新申请一份对象,那么就会调用一次框架函数,但是这个函数不建议频繁的申请,应该是担心内存碎片的大量产生。

2.用户调用流程不合理可能得到非预期结果

报盘框架对业务提供了打点的功能,业务需要在进行打点时,先调用获取报盘下行上下文接口,但是打点结束是在报盘插件中进行的,这样话,必须强制与业务做好限制。在下面情况下可能出现风险。

业务人员不熟悉流程,调用了调用获取报盘下行上下文接口,而未执行报盘插件中发送消息的接口,导致内存泄漏。

业务人员调用了获取报盘下行上下文接口,但是在执行业务函数时因为报错,函数直接返回,并未执行报盘插件中发送消息的接口,导致内存泄漏。

业务人员也有可能只执行了报盘插件中发送消息的接口,导致报盘下行上下文未初始化。

个人建议:发送消息的函数里不要包含打点结束的功能,另外对用户使用的错误,有日志输出。

3.线程局部变量与线程栈内存不合理的搭配使用

这种问题类似返回函数栈空间的引用或者指针,都会出现无法的地址访问。

4. 不合时宜的dlclose库句柄

当某个动态库包含thread_local自定义类变量时,调用者如果在存在thread_local变量的线程未结束前,就dlclose库句柄,那么当线程退出时会发生崩溃。这是因为dlcose后,库被卸载(对应的虚拟地址也不存在了),当调用者里的线程结束时,线程局部变量副本会自动调用析构函数,这时候访问不存在的地址,那么就会崩溃。当把线程局部变量改成指针类型后,便不会出现这个问题,这是因为不需要调用析构函数。

        当业务库使用线程局部存储变量时需要小心,调用者需要做好流程控制。

5.同线程的跨模块的递归调用,可能影响你的业务处理

对外提供的函数中包含了thread_local变量,你无法预测外界如何调用它,需要考虑当前线程是否已经存在了被使用过的thread_local变量,因为你可能调用多次这个变量对象的函数了,它会使得逻辑出错。

6.dlclose() 不调用全局对象的析构函数

(静态)全局变量尽量不用使用!!!!他在dlclose库时,析构的顺序有可能是不可预测的,这在跨平台开发时是有风险的。特别是搭配thread_local变量时,线程中的线程局部存储(副本)在随着线程消亡而需要资源释放资源时,遇到4的情况,就会出现崩溃。

总结

用thread_local的意义,简化代码,声明一次,但是使得每个线程启动时使用独有一份副本,不用每个线程执行时再通过代码管理这份资源。当我们(实现)维护代码时,发现不同的线程都想使用同一个变量,又不想使用锁,使用它再合适不过了。但是在跨库使用时,需要做好资源管理,避免使用全局静态变量,提供优雅的资源释放接口,不依赖系统的自动释放规则。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值