当前位置: 首页 > news >正文

C++八股 —— 线程本地存储技术

文章目录

    • 一、基本概念
    • 二、底层机制
    • 三、C++实现(C++11)
      • 1. 基本用法
      • 2. 线程局部静态变量
      • 3. 线程局部缓存
    • 四、性能特点及应用场景
      • 1. 性能特点
      • 2. 应用场景

面试问题:

一般情况下,单例模式创建的对象在一个进程中是所有线程共享一个的,如果需要一个线程有一个单独的单例对象应该如何实现?

答案:使用线程本地存储技术

一、基本概念

什么是线程本地存储

线程本地存储(Thread Local Storage, TLS) 是一种存储机制,其中变量不是被所有线程共享,而是每个线程都有该变量的独立副本

核心特性

  • 线程隔离:每个线程看到的变量值不同
  • 自动管理:线程创建时分配,线程结束时自动释放
  • 静态生命周期:类似静态变量,但每个线程独立
  • 访问效率:通常通过线程特定的指针表快速访问

二、底层机制

  1. 操作系统层面的实现原理

    • Windows系统

      // Windows 使用 TLS 索引机制
      DWORD tls_index = TlsAlloc();  // 分配 TLS 索引// 在每个线程中设置/获取 TLS 值
      TlsSetValue(tls_index, thread_data);
      void* data = TlsGetValue(tls_index);// 释放 TLS 索引
      TlsFree(tls_index);
      
    • POSIX (pthread) TLS

      // POSIX 线程使用 pthread_key_t
      pthread_key_t key;// 创建 TLS 键,可指定析构函数
      pthread_key_create(&key, destructor_function);// 在每个线程中设置/获取 TLS 值
      pthread_setspecific(key, thread_data);
      void* data = pthread_getspecific(key);// 删除 TLS 键
      pthread_key_delete(key);
      
  2. 内存布局

    进程内存空间
    ├── 全局变量区 (所有线程共享)
    ├── 堆区 (所有线程共享)
    ├── 每个线程的栈
    │   ├── 线程1栈
    │   ├── 线程2栈
    │   └── ...
    └── TLS 区域├── 线程1的TLS副本├── 线程2的TLS副本└── ...
    
  3. TLS内存模型

    Thread Control Block (TCB)
    ├── 线程ID
    ├── 栈指针
    ├── 其他线程信息
    └── TLS 块指针 → TLS 内存块├── TLS 变量 1├── TLS 变量 2├── ...└── TLS 变量 N
    

三、C++实现(C++11)

1. 基本用法

代码

#include <iostream>
#include <thread>
#include <vector>// 声明线程局部变量
thread_local int thread_specific_value = 0;
thread_local std::string thread_name = "unknown";void worker(int id) {// 每个线程有独立的变量副本thread_specific_value = id * 100;thread_name = "Worker-" + std::to_string(id);std::cout << "Thread " << std::this_thread::get_id() << ": value = " << thread_specific_value<< ", name = " << thread_name << std::endl;// 修改变量不影响其他线程thread_specific_value += 50;std::cout << "Modified value: " << thread_specific_value << std::endl;
}int main() {std::vector<std::thread> threads;// 主线程也有自己的 TLS 副本thread_specific_value = 999;thread_name = "MainThread";// 创建多个工作线程for (int i = 1; i <= 3; i++) {threads.emplace_back(worker, i);}// 主线程的 TLS 值保持不变std::cout << "Main thread value: " << thread_specific_value << std::endl;for (auto& t : threads) {t.join();}return 0;
}

输出

Main thread value: 999
Thread 140245316257536: value = 100, name = Worker-1
Thread 140245307864832: value = 200, name = Worker-2
Modified value: 150
Thread 140245299472128: value = 300, name = Worker-3
Modified value: 250
Modified value: 350

2. 线程局部静态变量

线程隔离的单例模式实现

class ThreadLocalDatabase {
private:ThreadLocalDatabase() {std::cout << "Database connection created for thread: " << std::this_thread::get_id() << std::endl;}public:static ThreadLocalDatabase& getInstance() {// 每个线程有独立的静态实例static thread_local ThreadLocalDatabase instance;return instance;}void query(const std::string& sql) {std::cout << "Thread " << std::this_thread::get_id()<< " executing: " << sql << std::endl;}// 禁止拷贝ThreadLocalDatabase(const ThreadLocalDatabase&) = delete;ThreadLocalDatabase& operator=(const ThreadLocalDatabase&) = delete;
};void database_worker(int id) {auto& db = ThreadLocalDatabase::getInstance();db.query("SELECT * FROM table WHERE id = " + std::to_string(id));
}

3. 线程局部缓存

#include <unordered_map>
#include <mutex>class ThreadLocalCache {
private:// 每个线程有自己的缓存映射thread_local static std::unordered_map<std::string, std::string> cache_;// 共享数据的保护锁(所有线程共享)static std::mutex global_mutex_;public:static std::string get(const std::string& key) {// 首先检查线程局部缓存auto it = cache_.find(key);if (it != cache_.end()) {return it->second;}// 缓存未命中,从共享数据源获取std::lock_guard<std::mutex> lock(global_mutex_);std::string value = fetch_from_global_source(key);// 存入线程局部缓存cache_[key] = value;return value;}static void clear() {cache_.clear();}private:static std::string fetch_from_global_source(const std::string& key) {// 模拟从数据库或网络获取数据return "value_for_" + key;}
};// 静态成员定义
thread_local std::unordered_map<std::string, std::string> ThreadLocalCache::cache_;
std::mutex ThreadLocalCache::global_mutex_;

四、性能特点及应用场景

1. 性能特点

优点

  • 无锁访问:不需要同步机制
  • 缓存友好:数据在线程本地,减少缓存一致性开销
  • 可扩展性:随着线程数增加性能线性扩展

缺点

  • 内存开销:每个线程都有变量副本
  • 初始化成本:线程创建时需要初始化 TLS
  • 访问成本:比普通全局变量稍慢(需要间接寻址)

2. 应用场景

适合使用 TLS 的场景

  1. 数据库连接:每个线程独立的连接对象
  2. 用户会话:Web 服务器中的用户上下文
  3. 随机数生成器:线程独立的随机状态
  4. 性能统计:每个线程的操作计数
  5. 内存分配器:线程局部的内存池
  6. 错误处理:线程特定的错误状态
  7. 本地缓存:线程局部的查找缓存

不适合使用 TLS 的场景

  1. 需要线程间共享的数据
  2. 内存极度受限的环境
  3. 创建大量短期线程的场景
  4. 需要严格顺序执行的操作

参考:DeepSeek

http://www.dtcms.com/a/461988.html

相关文章:

  • 位运算题5:出现k次与出现1次
  • 我们为什么需要Agent?
  • MLMs之Sora:Sora 2(开启真实物理与创意融合的新一代视频生成平台)的简介、安装和使用方法、案例应用之详细攻略
  • (1)100天python从入门到拿捏
  • 昆明网站定制制作logo网站
  • 个人做哪方面的网站网站续费怎么做
  • Differential evolution with collective ensemble learning
  • 东莞网站推广策划wordpress怎么改标题和meta
  • jquery mvvm框架
  • 做外贸的几个网站如何添加网站白名单
  • 统一 IT 服务台平台:让企业服务运转更高效
  • 在线做c语言题目的网站免费自助在线公司起名
  • 70行代码展现我的“毕生”编程能力
  • C++ List
  • 从指令到智能:大型语言模型提示词工程与上下文工程的综合分析
  • wordpress清理过期文件夹电商seo
  • html网站尺寸成立公司需要哪些资料
  • 物联网边缘节点中的MEMS传感器低功耗设计实战
  • 当工业生产遇上RFID:智能追溯让制造全流程“透明可见”
  • LeetCode 刷题【109. 有序链表转换二叉搜索树】
  • 建设企业网站模板下载黑龙江省建设工程质量安全协会网站
  • VMware 安装 Ubuntu 24.04(稳定版本) 母胎教学
  • 巴城镇建设网站微信微网站制作公司
  • Linux 系统配置 NTP 服务:轻松同步阿里云时间服务器
  • 网站建设公司列表网加强网站建设工作
  • 深度学习之模型的部署、web框架 服务端及客户端案例
  • 《投资-113》价值投资者的认知升级与交易规则重构 - 复利故事终止的前兆
  • 从 “黑盒“ 到 “透明“:SkyWalking 实战指南 —— 让微服务问题无所遁形
  • 网站流量增加专门做物理的网站
  • 鸿蒙应用开发从入门到实战(十七):ArkUI组件List列表布局