聊聊Linux中的线程本地存储(1)——什么是TLS

linux中的线程局部存储(TLS)实现线程间的同步和互斥pthread_key_create、pthread_setspecific、pthread_getspecific 由于线程局部存储是基于操作系统的特性,因此它可能会受到操作系统实现的影响。不同的操作系统可能会有不同的线程局部存储实现和限制。 阅读详情

从本篇开始进入另一个话题:线程本地存储(Thread Local Storage),在介绍这个概念前先说说变量和多线程的相关知识。

多线程下的变量模型

在单线程模型下,变量定义有两个维度,那就是在何处定义,以及它的修饰属性(static, extern,auto,register等)。extern属性表示声明一个变量 ,与定义无关,在此不作讨论;而register是将变量优化成寄存器里面,不作讨论。与变量定义相关的修饰属性就只有auto和static了。这两个维度可以得到变量的类型,以及它们的行为。评价一个变量的行为,通过常是从可见性和
生命周期两方面评定的,下面将变量的“何处定义”和“修饰属性”,得出“变量类型”以及从“可见性”和“生命周期”列出一个完整的表格,如下:

何处定义修饰属性变量类型生命周期可见性
在函数外auto全局变量整个程序全局可见
在函数外static全局静态变量整个程序同一.c文件可见
在函数内auto局部变量函数开始执行到结束这段时间函数内可见
在函数内static静态局部变量整个程序函数内可见

对于静态局部变量会有这样的疑问,它只能在函数内使用,为什么它的生命周期是全局的?其实它与局部变量是不一样的,局部变量在函数开始执行时,才创建出来的,在函数执行结束时,它就消失了,不存在了。而静态局部变量,在函数没有执行时,它就已经在存在了,这就是为什么说它是整个程序的生命周期。当函数执行结束之后,它仍然存在,下次再执行该函数时,它是基于之前执行后的结果,开始执行的。所以它的行为与全局变量是一样的,不同之外是只能在函数内才能对它进行访问。

在单线程编程下面,这一切都协调得很好。因为整个进程只有一个执行单元,何任时刻只有一个执行代码(或者函数)在访问同一变量。

然而在多线程模式下,这一切都发生了变化。在多线程模式下面,同时出现多个执行单元,也即同一个函数会同时在多个执行单元中运行

提起多线程,几乎都想起应用加锁进行保护数据,但这不是充分必要的。

局量变量(生命周期在函数内的)是不受多线程影响,因为每个线程栈是独立的,多个线程同时执行该函数,访问局变部变量都是每线程一份的,不会产生数据竞争(race)。

但对于生命周期为整个程序的全局变量、全局静态变量和静态局部变量就不是那么一回事了。多线程下出现多个执行单元同时访问该变量,会出现数据竞争。在这种情况下,必须使用加锁进行数据保护,才能保证程序逻辑的正确性。

提起加锁,直觉反应就是将部分代码又回到串行执行的时代,如果加锁很频繁,那整个进程能并发执行的代码比例并不高,使用多线程带来的加速比并不高,最重要的是无法根据处理器个数来动态伸缩。

在多程线程序设计中,很多时候对数据进行划分,不同的数据区域交给不同的线程处理,可以避免多线程中竞争访问数据。但是有一个问题得考虑,那就是:各个独立线程在执行函数时(通常是不同线程执行相同的函数,只是他们访问的数据不同),这些函数的中间输出结果能否已是线程独立的呢?如果能完全独立,则多线程之间完全不需要互斥,伸缩性最优。

这个问题有两个解决办法,首先想到的是这些函数的输入和输出全部用参数传递。但它对编程要求很高, 有时这样的设计往往并不是最优的。很多时候函数的中间输出结果需要使用全局变量来保存(当然我们不推荐全局变量满天飞,但在一个模块内的静态全局变量还是常有的),这样就需要加锁保护,效率低下。

在这个场景下,每个线程都希望自己看到的全局变量是自己的,它也不想看到别人的,也不想别人对它有修改,它也不想修改别人的,全局变量也是个形式而已,最终目的是它可以独立拥有一份。

那么要解决多线程下的高效编程问题,必须对原来的变量模型稍作修改,支持一个额外的属性,那就是变量是多执行单元(线程)共享还是独立拥有一份。

何处定义修饰属性多执行单元共享or独享变量类型生命周期可见性
在函数外auto共享全局变量整个程序全局可见
在函数外auto独享全局线程变量整个程序全局可见
在函数外static共享全局静态变量整个程序同一.c文件可见
在函数外static独享全局静态线程变量整个程序同一.c文件可见
在函数内auto独享局部变量只在函数开始执行到结束这段时间函数内
在函数内static共享静态局部变量整个程序函数内可见
在函数内static独享静态局部线程变量整个程序函数内可见

注意,局部变量本来就是线程函数内独享的,所以它没有共享这个属性值,整个程序生命周期的变量都有共享和独享这两个属性值。

什么是TLS

写到这里,TLS的定义就不言而喻。TLS全称为Thread Local Storage,即线程本地存储。在单线程模式下,所有整个程序生命周期的变量都是只有一份,那是因为只是一个执行单元;而在多线程模式下,有些变量需要支持每个线程独享一份的功能。这种每线程独享的变量放到每个线程专有的存储区域,所以称为线程本地存储(Thread Local Storage)或者线程私有数据(Thread Specific Data)。

Linux下支持两种方式定义和使用TLS变量,具体如下表:

定义方式支持层次访问方式
__thread关键字语言层面与全局变量完全一样
pthread_key_create函数运行库层面pthread_get_specific和pthread_set_specific对线程变量进行读写

应用语言支持的__thread关键字是最简单的,只须在定义变量时增加一个__thread关键字,后续对该变量的访问方式完全保持不变,所以这个是语言级别上的支持,属于隐式支持。_thread关键字是gcc对C语言的扩展,不是C语言标准定义的,当然Windows下的Visual Stdio也使用另一个关键字做扩展。

__thread例子

下面使用简单的例子说明__thread关键字的用法,以及实际的效果。

__thread int var = 0;   // var定义为线程变量,每个数线拥有一份

void* worker(void* arg);  

int main(){  
    pthread_t pid1,pid2;  

    pthread_create(&pid1,NULL,worker,(void *)0);  
    pthread_create(&pid2,NULL,worker,(void *)1);  

    pthread_join(pid1,NULL);  
    pthread_join(pid2,NULL);  

    return 0;  
}  
void* worker(void* arg){  
    int idx = (int)arg;
    int i;

    for (i = 0; i < 100; ++i) {
        printf("thread:%d  ++var = %d\n", idx, ++var); // 每个线程只访问自己独享的那份
    }
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

使用pthread_key_create/pthread_get_specific/pthread_set_specific函数创建和使用的线程变量,在后面的会作相应的介绍,我们暂时不作讨论。

后面文章中,我们使用线程变量这一术语表示每线程独享一份的变量,而使用TLS述语来表示对这一类变量存储属性的统称。

从逆向工程到软件防护:基于Exeinfo PE与OllyDbg的攻防实战 逆向工程是分析软件内部运行机制、理解程序逻辑的关键技术,其核心原理在于通过静态与动态分析手段,解析二进制可执行文件的结构与行为。在软件安全领域,逆向分析不仅用于漏洞挖掘,更是构建有效防护体系的技术基础。通过Exeinfo PE等工具进行静态特征分析(如识别编译器、探测保护壳、检查导入表),可以评估软件的暴露面;而OllyDbg等动态调试器则能深入跟踪程序执行流,揭示核心验证算法与潜在弱点。这种“以攻促防”的思维,其技术价值在于能将攻击手法转化为防护设计,例如针对静态分析采用代码混淆、字符串加密,针对动态调试 阅读详情

相关推荐

JNI性能优化深度解析:从原理到实战的极致调优指南

在跨语言编程领域,Java Native Interface(JNI)作为连接Java虚拟机与本地C/C++代码的核心桥梁,其性能表现直接影响着系统级应用的效率。理解JNI的工作原理,关键在于掌握其内存管理机制、数据类型转换开销以及虚拟机与本地代码间的交互协议。从技术价值看,JNI优化能显著降低跨语言调用的延迟,提升数据处理吞吐量,这对于构建高性能系统至关重要。在实际应用场景中,无论是移动端应用的启动加速、游戏引擎的实时渲染,还是后端服务的高并发处理,都离不开对JNI性能的精细调优。本文聚焦于JNI性能优化

weixin_34409357的博客 545

玩转代码|Linux中Thread Local Storage(线程局部存储)

在C/C++程序中,全局变量默认是所有线程共享的,开发者需要处理多线程竞争问题。有些情况下我们需要保证一个线程独享一份数据,其它线程无法访问。典型的就是errno全局变量,它总是会保存当前线程最后一个调用的错误码,不会存在线程冲突。这个时候需要使用线程局部存储(TLS)来解决。

Jum的博客 2036

C++性能优化实战:从CPU缓存到并发编程的完整指南

性能优化是软件工程中的核心议题,尤其在系统级编程和高性能计算领域。其原理根植于对计算机体系结构的深刻理解,包括CPU缓存层次结构、指令流水线、分支预测以及内存访问模式等硬件行为。从技术价值看,有效的优化能显著提升程序执行效率、降低资源消耗,并直接影响用户体验和系统吞吐量。在应用场景上,无论是游戏引擎、高频交易系统,还是大规模数据处理和实时服务,性能优化都是保障竞争力的关键。本文聚焦于C++这一高性能编程语言,深入探讨如何通过**缓存友好**的代码设计和**编译器优化**策略,系统性地提升程序性能,涵盖从硬件

babing2770的博客 432

linux多线程:tls的实现方式

在Linux系统中使用C/C++进行多线程编程时,我们遇到最多的就是对同一变量的多线程读写问题,大多情况下遇到这类问题都是通过锁机制来处理,但这对程序的性能带来了很大的影响,当然对于那些系统原生支持原子操作的数据类型来说,我们可以使用原子操作来处理,这能对程序的性能会得到一定的提高。那么对于那些系统不支持原子操作的自定义数据类型,在不使用锁的情况下如何做到线程安全呢?本文将从线程局部存储方面,简单讲解处理这一类线程安全问题的方法。 1、数据类型 在C/C++程序中常存在全局变量、函数内定义的静态变量以及

4395

Python+Selenium实现抖音博主批量监控:300+账号实时更新通知(附完整代码)

本文详细介绍了如何使用Python和Selenium构建一个高可用的抖音博主批量监控系统。通过架构设计、Cookie管理、高效轮询与差异检测等核心模块,实现300+账号的实时更新追踪与通知。文章提供了完整的代码实现,并重点探讨了性能优化、异常处理及服务器部署等实战经验,帮助开发者打造稳定、可控的自动化监控解决方案。

weixin_29274969的博客 196

验证(uvm常见问题)--子类和父类的句柄和对象问题

sv中的子类和父类 在sv中,有如下两个类,child继承于parent。然后在test module中,正确转换的方法如下面所示。其中c1,c2,p1 都指向了同一个子类的对象c1。总结如下: 一个子类的对象是包括子类的成员变量,方法和父类的成员变量,方法。 子类的句柄c1可以直接赋值给父类的句柄p1,此时p1只可以访问父类的成员变量和方法,或者子类的虚方法,比如下面调用p1.display是...

q876507447的博客 7633

Linux中web服务器的TLS 协议搭建

一 1、网络传输安全: 我们需要加密网络数据以实现安全通信,但是有一个现实的问题: 1.非对称加密算法(RSA/ECC 等)可以方便地对数据进行签名/验证,但是计算速度慢。 2.对称加密算法(ChaCha20/AES 等)计算速度快,强度高,但是无法安全地生成与保管密钥。 TLS 通过两个证书来实现服务端身份验证,以及对称密钥的安全生成: 1.CA 证书:浏览器/操作系统自带,用于验证服务端的 TLS 证书的签名。保证服务端证书可信。 2.TLS 证书:使用 CA 证书验证了 TLS 证书可信后,将使用这个

学习日常分享 3657

别再手动调参了!用MATLAB+改进PSO算法,5步搞定机械臂轨迹优化(附完整代码)

本文介绍如何利用MATLAB和改进PSO算法快速优化机械臂轨迹规划,仅需5步即可完成传统耗时的手动调参过程。通过混沌初始化、自适应权重等创新方法,改进PSO算法显著提升优化效率,实现全局最优解搜索,适用于工业自动化中的机械臂控制。文章包含完整MATLAB代码实现,帮助工程师轻松应用于实际生产场景。

weixin_29232121的博客 356

TLS linux线程本地存储,聊聊Linux中的线程本地存储(1)——什么是TLS

从本篇开始进入另一个话题:线程本地存储(Thread Local Storage),在介绍这个概念前先说说变量和多线程的相关知识。多线程下的变量模型在单线程模型下,变量定义有两个维度,那就是在何处定义,以及它的修饰属性(static, extern,auto,register等)。extern属性表示声明一个变量 ,与定义无关,在此不作讨论;而register是将变量优化成寄存器里面,不作讨论。与...

weixin_39620001的博客 337

Win10系统下AppScan 10.0.0安装破解全流程(附百度网盘资源)

本文详细介绍了在Windows 10系统上安装和配置AppScan 10.0.0进行Web漏洞扫描的完整流程。内容涵盖环境准备、分步安装、核心文件部署、许可证配置及首次扫描实践,旨在帮助开发人员和安全爱好者快速搭建专业的Web应用安全扫描环境,并提升扫描效率。

u8v9w0x1y的博客 367

ESP32系列之LVGL(四):输入设备(外部按键)对接

本文详细介绍了如何在ESP32上使用LVGL库对接外部按键作为输入设备,包括硬件连接、驱动层实现和LVGL输入设备移植。通过具体代码示例和实战案例,帮助开发者快速实现按键控制UI界面,解决常见问题如按键无反应和控件跳转不正常。

weixin_30907935的博客 242

线程本地存储 TLS

线程本地存储 TLS(静态TLS) TLS的概念,以下链接讲的比较详细 静态TLS TLS的应用 总结 线程本地存储 TLS(静态TLS) TLS的概念,以下链接讲的比较详细 聊聊Linux中的线程本地存储(1)——什么是TLS 静态TLS 上面链接中提到__thread关键字是GCC编译器的扩展,并不属于标准,所以在window下的VC++是没有这...

mo4776的博客 562

ImageNet分类实战:用PyTorch复现AlexNet的5个关键技巧(附代码)

本文详细介绍了使用PyTorch复现经典AlexNet模型进行ImageNet图像分类的五个关键工程技巧。内容涵盖模型架构的现代重构、训练策略优化、核心组件实现与替代方案,以及实用的训练调试方法,并提供了完整的代码示例,帮助开发者深入理解深度卷积神经网络的实现细节与优化思路。

i0j1k2l3m的博客 94

【linux 多线程并发】线程本地数据存储的两种方式,每个线程可以有同名全局私有数据,以及两种方式的性能分析

现代的CPU都是多core处理器,而且在intel处理器中每个core又可以多个processor,形成了多任务并行处理的硬件架构,在服务器端的处理器上架构又有一些不同,传统的采用SMP,也就是对称的多任务处理架构,每个任务都可以对等的访问所有内存,外设等,而如今在ARM系列CPU上,多采用NUMA架构,它将CPU核分了几个组,给每个组的CPU core分配了对应的内存和外设,CPU访问对应的内存和外设时速度最优,跨组访问时性能会降底一些。

一个追逐梦想的码农 7407

宋浩线性代数笔记

Miao-A-SongHao-Linear-Algebra-Notes bilibili 宋浩老师 “惊叹号” 系列 《线性代数》网课 笔记及时间点目录 Github项目地址:https://github.com/cy69855522/Miao-A-SongHao-Linear-Algebra-Notes ???? 前言 我发现吧,线代没记笔记真不行。 浩浩学习,天天向上。数学网课推荐????宋浩老师的免...

Knife丶小刀博客 4万+

18、近端策略优化(PPO)算法详解

本文详细介绍了近端策略优化(PPO)算法的理论基础、算法流程、实现方法及实际应用。PPO作为当前最受欢迎的策略梯度算法之一,具有易于实现、计算成本低、样本效率高和性能优越等优点。文章对比了基于自适应KL惩罚和基于裁剪目标的两种PPO变体,重点解析了裁剪目标函数的设计原理及其在Actor-Critic框架下的实现方式,并通过Atari Pong游戏展示了完整的训练配置与流程。最后总结了PPO的优势、适用场景及未来发展方向,为强化学习研究者和实践者提供了全面的参考。

mongodb5scout的博客 180

Linux中的线程局部存储(二)

在 Linux中还有一种更为高效的线程局部存储方法,就是使用关键字__thread来定义变量。__thread是GCC内置的线程局部存储设施 (Thread-Local Storage),它的实现非常高效,与pthread_key_t向比较更为快速,其存储性能可以与全局变量相媲美,而且使用方式...

ciddk2085的博客 116

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Alpine镜像深度解析:从BusyBox、musl libc到PIE与glibc兼容性实战

在容器化与云原生技术实践中,基础镜像的选择直接影响着应用部署的效率、安全性与资源消耗。Docker镜像作为应用打包与分发的标准单元,其构建原理涉及操作系统核心组件与编译工具链的协同工作。其中,C标准库(如glibc与musl libc)与动态链接机制是确保应用可移植性的技术基石,而位置无关可执行文件(PIE)等安全编译选项则进一步增强了内存防护能力。这些底层技术共同决定了镜像的兼容性、体积与性能,对于构建高效、稳定的容器化应用具有重要工程价值。本文聚焦于轻量级Linux发行版Alpine,深入探讨其采用Bu

weixin_30240349的博客 445

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Qemu沙箱逃逸漏洞分析:从MMIO越界到虚拟化隔离突破

内存安全是软件安全的基石,其核心原理在于对程序内存访问的严格边界控制。当程序(如Qemu设备模拟代码)未能正确验证输入数据的边界时,便可能产生缓冲区溢出等内存破坏漏洞,直接威胁系统安全。这类漏洞的技术价值在于,它们往往能绕过高级别的隔离机制,例如虚拟化层(Hypervisor)为虚拟机(Guest)构建的沙箱环境。在云计算和虚拟化场景中,攻击者可能利用此类漏洞,从一台虚拟机内部突破隔离,进而影响宿主机或其他租户,即实现“沙箱逃逸”。本文以一次真实的内部攻防演练为背景,深入剖析一个由**内存越界**漏洞引发的

cunfuteng7334的博客 401

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

从API调用者到系统构建者:掌握底层技术原理的实战指南

在软件开发领域,深入理解底层技术原理是提升工程能力的关键。从计算机科学基础概念出发,操作系统、网络协议和数据库等核心组件构成了现代应用系统的基石。其技术价值在于,开发者能超越框架API的简单使用,从被动应对问题转变为主动构建高效、稳定的系统。例如,理解JVM内存模型与垃圾回收机制,可以精准诊断内存泄漏;掌握I/O多路复用原理,能设计出支撑高并发的网络服务。在实际应用场景中,无论是优化秒杀系统的性能,还是解决分布式环境下的数据一致性问题,都需要综合运用这些底层知识进行权衡与设计。本文聚焦于JVM、TCP/IP

weixin_33957648的博客 363

基于io_uring与C++构建百万级QPS高并发网络引擎实战

在Linux高性能网络编程领域,异步I/O模型是支撑高并发服务的核心技术。其原理在于通过事件驱动机制,将I/O操作从阻塞等待转为异步通知,从而大幅提升系统吞吐量。传统方案如epoll虽广泛应用,但在追求极致性能时,其频繁的系统调用和内存拷贝开销成为瓶颈。io_uring作为Linux内核近十年的重大革新,通过共享内存环形队列实现了真正的异步与批处理,将用户态与内核态的交互开销降至最低,技术价值在于为百万级QPS场景提供了新的底层支撑。这一特性使其特别适用于网关、代理、实时通信等对延迟和吞吐量要求苛刻的应用场

weixin_34198762的博客 445

多种方法在Linux上检查tls版本

在这个例子中,我们连接到example.com的443端口,并指定使用TLS 1.2版本。无论使用哪种方法,检查TLS版本是确保系统安全和加密通信的重要步骤。确保系统上使用的TLS版本是最新且安全的,以保护你的数据和隐私。这个Python脚本使用socket和ssl模块来连接到example.com的443端口,并输出所使用的TLS版本。这将扫描example.com的443端口,并列出支持的TLS版本。在输出中,你可以看到连接信息,其中包括所使用的TLS版本。

nb1253587023的博客 1万+

linux中线程局部存储(TLS)

我们知道术语每个线程私有的数据包括线程的栈和当前的寄存器,但时这两种存储都是非常不可靠的,栈会在每个函数退出和进入的时候被改变;如果我们要在线程中使用一个全局变量,但希望这个全局变量时线程私有得,而不是所以线程共享得,该怎么办呢?TLS得用法很简单,如果要定义一个全局变量TLS类型得,只需要在它签名加上相应得关键字即可。一旦一个全局变量被定义成TLS类型得,那么每个线程都会拥有这个变量得一个副本,任何线程对该变量得修改都不会影响其他线程中该变量得副本。可见地址都不一样,线程之间相互不影响。

zhaoyangwyyx的博客 710

透过__thread学线程局部存储(TLS)

1. 简介   线程局部存储,英文为Thread Local Storage,缩写为TLS。   在一个线程修改的内存内容,对所有线程都生效。这是一个优点也是一个缺点。说它是优点,线程的数据交换变得非常快捷。说它是缺点,一个线程死掉了,其它线程也性命不保; 多个线程访问共享数据,需要昂贵的同步开销,也容易造成同步相关的BUG。   如果需要在一个线程内部的各个函数调用都能访问、但其它线程不能访

海之凌云的博客 939

Linux C语言程序中线程本地存储变量的内存分配和使用

在多线程中,有一种叫线程本地存储(Thread-Local Storage,TLS)的变量,它是每个线程有且只有一份自己的副本,对于这个线程来说,它是全局变量,可被所有函数共用;因为每个线程都有自己的一份内存来存储这些变量,所以线程之间不会相互干扰。TLS变量的内存分配和释放是由操作系统自动管理的,程序员无需手动分配和释放内存。同时,由于每个线程都有自己独立的一份副本,因此TLS变量的读写不需要加锁,可以提高多线程程序的性能。邀请您加入「社区资讯服务」创业微信群,共同探讨打造社区资讯服务的美好未来。

qiuzen的博客 1335
上一篇: c++ Lambda函数学习
下一篇: C++ STL 学习 :for_each与仿函数(functor)
killmice
博客等级 码龄14年 119粉丝 54原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值