线程局部存储

【C++】线程局部存储 通过线程局部存储,可以实现线程间数据的独立管理,提高了多线程编程的灵活性和安全性。 阅读详情

为什么要有TLS?原因在于,进程中的全局变量与函数内定义的静态(static)变量,是各个线程都可以访问的共享变量。在一个线程修改的内存内容,对所有线程都生效。这是一个优点也是一个缺点。说它是优点,线程的数据交换变得非常快捷。说它是缺点,一个线程死掉了,其它线程也性命不保; 多个线程访问共享数据,需要昂贵的同步开销,也容易造成同步相关的BUG。

  如果需要在一个线程内部的各个函数调用都能访问、但其它线程不能访问的变量(被称为static memory local to a thread 线程局部静态变量),就需要新的机制来实现。这就是TLS。

  线程局部存储在不同的平台有不同的实现,可移植性不太好。幸好要实现线程局部存储并不难,最简单的办法就是建立一个全局表,通过当前线程ID去查询相应的数据,因为各个线程的ID不同,查到的数据自然也不同了。

  大多数平台都提供了线程局部存储的方法,无需要我们自己去实现:

  linux:

  int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));

  int pthread_key_delete(pthread_key_t key);

  void *pthread_getspecific(pthread_key_t key);

  int pthread_setspecific(pthread_key_t key, const void *value);

  Win32

  方法一:每个线程创建时系统给它分配一个LPVOID指针的数组(叫做TLS数组),这个数组从C编程角度是隐藏着的不能直接访问,需要通过一些C API函数调用访问。首先定义一些DWORD线程全局变量或函数静态变量,准备作为各个线程访问自己的TLS数组的索引变量。一个线程使用TLS时,第一步在线程内调用TlsAlloc()函数,为一个TLS数组索引变量与这个线程的TLS数组的某个槽(slot)关联起来,例如获得一个索引变量:

  global_dwTLSindex=TLSAlloc();

  注意,此步之后,当前线程实际上访问的是这个TLS数组索引变量的线程内的拷贝版本。也就说,不同线程虽然看起来用的是同名的TLS数组索引变量,但实际上各个线程得到的可能是不同DWORD值。其意义在于,每个使用TLS的线程获得了一个DWORD类型的线程局部静态变量作为TLS数组的索引变量。C/C++原本没有直接定义线程局部静态变量的机制,所以在如此大费周折。

  第二步,为当前线程动态分配一块内存区域(使用LocalAlloc()函数调用),然后把指向这块内存区域的指针放入TLS数组相应的槽中(使用TlsValue()函数调用)。

  第三步,在当前线程的任何函数内,都可以通过TLS数组的索引变量,使用TlsGetValue()函数得到上一步的那块内存区域的指针,然后就可以进行内存区域的读写操作了。这就实现了在一个线程内部这个范围处处可访问的变量。

  最后,如果不再需要上述线程局部静态变量,要动态释放掉这块内存区域(使用LocalFree()函数),然后从TLS数组中放弃对应的槽(使用TlsFree()函数)。

在多线程程序中,经常要用全局变量来实现多个函数间的数据共享。由于数据空间是共享的,因此全局变量也为所有进程共有。但有时应用程序设计中必要提供线程私有的全局变量,这个变量仅在线程中有效,但却可以跨过多个函数访问。

比如在程序里可能需要每个线程维护一个链表,而会使用相同的函数来操作这个链表,最简单的方法就是使用同名而不同变量地址的线程相关数据结构。这样的数据结构可以由 Posix 线程库维护,成为线程私有数据 (Thread-specific Data,或称为 TSD)。

这里主要测试和线程私有数据有关的 4 个函数:

pthread_key_create();
pthread_key_delete();

pthread_getspecific();
pthread_setspecific();

程序代码:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_key_t  key;
struct  test_struct  {
     int  i;
     float  k;
};
void  * child1 ( void  * arg)
{
     struct  test_struct  struct_data;
     struct_data . i  =  10;
     struct_data . k  =  3.1415;
     pthread_setspecific ( key ,  & struct_data);
     printf ( "结构体struct_data的地址为 0x%p \n " ,  &( struct_data));
     printf ( "child1 中 pthread_getspecific(key)返回的指针为:0x%p \n " , ( struct  test_struct  *) pthread_getspecific( key));
     printf ( "利用 pthread_getspecific(key)打印 child1 线程中与key关联的结构体中成员值: \n struct_data.i:%d \n struct_data.k: %f \n " , (( struct  test_struct  *) pthread_getspecific ( key)) -> i , (( struct  test_struct  *) pthread_getspecific( key)) -> k);
     printf ( "------------------------------------------------------ \n ");
}
void  * child2 ( void  * arg)
{
     int  temp  =  20;
     sleep ( 2);
     printf ( "child2 中变量 temp 的地址为 0x%p \n " ,   & temp);
     pthread_setspecific ( key ,  & temp);
     printf ( "child2 中 pthread_getspecific(key)返回的指针为:0x%p \n " , ( int  *) pthread_getspecific( key));
     printf ( "利用 pthread_getspecific(key)打印 child2 线程中与key关联的整型变量temp 值:%d \n " ,  *(( int  *) pthread_getspecific( key)));
}
int  main ( void)
{
     pthread_t  tid1 ,  tid2;
     pthread_key_create ( & key ,  NULL);
     pthread_create ( & tid1 ,  NULL , ( void  *) child1 ,  NULL);
     pthread_create ( & tid2 ,  NULL , ( void  *) child2 ,  NULL);
     pthread_join ( tid1 ,  NULL);
     pthread_join ( tid2 ,  NULL);
     pthread_key_delete ( key);
     return ( 0);
}


运行与输出:

 ./pthread_key 
结构体struct_data的地址为 0x0xb7699388
child1 中 pthread_getspecific(key)返回的指针为:0x0xb7699388
利用 pthread_getspecific(key)打印 child1 线程中与key关联的结构体中成员值:
struct_data.i:10
struct_data.k: 3.141500
------------------------------------------------------
child2 中变量 temp 的地址为 0x0xb6e9838c
child2 中 pthread_getspecific(key)返回的指针为:0x0xb6e9838c


由输出可见,pthread_getspecific() 返回的是与key 相关联数据的指针。需要注意的是,在利用这个返回的指针时,它首先是 void 类型的,它虽然指向关联的数据地址处,但并不知道指向的数据类型,所以在具体使用时,要对其进行强制类型转换。
其次,两个线程对自己的私有数据操作是互相不影响的。也就是说哦,虽然 key 是同名且全局,但访问的内存空间并不是相同的一个。key 就像是一个数据管理员,线程的私有数据只是到他那去注册,让它知道你这个数据的存在。

Windows 下实现线程局部存储 以下叙述的仅是Windows NT,XP 等系统下实现线程局部存储的一个思路,并不是绝对的实现方法。 线程局部存储(Thread Local Storage,TLS),是多线程普及的情况下一个很有用的机制,该机制使得线程可以使用属于自己的全局变量。只需要在一个全局变量的定义前加上相应的关键字,即可指定一个全局变量为TLS属性的。 GCC:__thread int number; Window 阅读详情

相关推荐

手把手教你用Matlab/Simulink搭建PMSM的SMO无感FOC仿真(附相位补偿与离散化代码)

本文详细介绍了基于滑模观测器(SMO)的永磁同步电机(PMSM)无传感器FOC控制方法,通过Matlab/Simulink平台实现从理论到实践的完整流程。内容涵盖SMO核心原理、离散化处理、转子位置估算与相位补偿技术,以及双闭环控制系统搭建,为工程师提供了一套完整的无传感器控制解决方案。

weixin_27038245的博客 253

TSD相关的 4 个函数: pthread_key_create(); pthread_key_delete(); pthread_getspecific(); pthread_sets

在多线程程序中,经常要用全局变量来实现多个函数间的数据共享。由于数据空间是共享的,因此全局变量也为所有进程共有。但有时应用程序设计中必要提供线程私有的全局变量,这个变量仅在线程中有效,但却可以跨过多个函数访问。 比如在程序里可能需要每个线程维护一个链表,而会使用相同的函数来操作这个链表,最简单的方法就是使用同名而不同变量地址的线程相关数据结构。这样的数据结构可以由 Posix 线程库维护,成

huangmeimao的专栏 1611

JFET放大电路实例设计仿真

参照《晶体管电路设计》中的例子 JFET 2SK184 JFET 2SK184 数据手册如下 电路设计 共源放大 步骤:1、静态工作点 2N4416 1ma 2、RD和RS A=5 5:1 RS 2V /1m=2k RD 5k 3、偏压VG 根据传输特性 VGS-ID vgs=-0.7 vg=2-0.7=1.3 400k^2/50k...

f的博客 7440

每天进步一点点——Linux中的线程局部存储(一)

在Linux系统中使用C/C++进行多线程编程时有些数据无需使用锁即可做到快速高效,本文从线程局部存储出发讨论如何高效的实现无锁编程。

Cynric 的博客 3万+

中介效应、调节效应与交互效应:从概念辨析到统计建模全指南

在社会科学与数据分析研究中,理解变量之间的因果关系与条件性影响是核心任务之一。回归分析作为最基础的统计工具,常被用于探索自变量对因变量的作用机制,而中介效应与调节效应则分别回答了“如何影响”与“何时影响不同”的深层问题。中介效应通过路径分析拆解因果链条,揭示内部的传导机制;调节效应则借助交互项识别影响的边界条件。Bootstrap法已成为检验间接效应的主流手段,而简单斜率分析则让调节作用的模式更加直观。无论是用户研究、医学统计还是产品数据分析,掌握这些模型都能帮助研究者构建更具解释力的实证框架。本文基于大量

weixin_29051149的博客 330

基于 ESP32 与 TDS 传感器的水培营养液离子浓度自动配比系统设计与实现

本系统以 ESP32 为主控芯片,结合 TDS(总溶解固体)传感器实时监测水培营养液中的离子浓度,通过蠕动泵自动补充浓缩营养液或清水,实现营养液 EC 值的闭环自动配比。系统适用于家庭及小型农场的水培种植场景,可稳定维持营养液浓度在作物生长所需的最佳区间。

weixin_42300449的博客 77

pthread_getspecific和pthread_setspecific详解

pthread_getspecific和pthread_setspecific详解

weixin_46935110的博客 2177

低功耗设计:rush current

在power gating的设计中引入了一个rush current的概念,它的产生原因是switch cell上电过程相当于电容充电过程,会产生一个短期的大电流,称之为rush current。 1.rush current的危害 1)造成巨大的ir drop 2)导致功能错误 3)一些极端例子中,rush current会引发VDD短期崩溃,造成存储在retention register与mem中的数据失效 4)大电流会还对周围always on模块造成干扰,产生大的压降 2.控制rus

m0_61544122的博客 3071

pthread

pthread 应用

black&white 595

PyTorch实战:卷积神经网络详解+Python实现卷积神经网络Cifar10彩色图片分类

PyTorch可以说是三大主流框架中最适合初学者学习的了,相较于其他主流框架,PyTorch的简单易用性使其成为初学者们的首选。这样我想要强调的一点是,框架可以类比为编程语言,仅为我们实现项目效果的工具,也就是我们造车使用的轮子,我们重点需要的是理解如何使用Torch去实现功能而不要过度在意轮子是要怎么做出来的,那样会牵扯我们太多学习时间。以后就出一系列专门细解深度学习框架的文章,但是那是较后期我们对深度学习的理论知识和实践操作都比较熟悉才好开始学习,现阶段我们最需要的是学会如何使用这些工具。

master_hunter的博客 8933

【报错解决】OpenClaw 报错 `openclaw: command not found`:全局命令未加入系统 PATH 的深度排查与修复指南

在国产AI工具链开发中,OpenClaw作为关键命令行工具常出现command not found报错。本文深度分析该问题的根源——Linux环境变量PATH未包含用户级安装目录(~/.local/bin)。通过四种解决方案(临时PATH修改、永久配置、软链接、虚拟环境处理)和排错Checklist,揭示"命令存在却找不到"的本质是路径配置问题,特别适用于Docker/国产Linux/非root环境。文中强调理解Linux工具链机制对国产AI开发的重要性,并指出这是开发者掌握环境

博客 5382

线程局部存储-pthread_getspecific和pthread_setspecific使用

转载。

qq_18447271的博客 1399

影楼精修-肤色统一算法解析

本文介绍了影楼精修中肤色统一算法的实现方案,并以像素蛋糕软件为例进行详细分析。肤色统一旨在通过调整人像照片中皮肤区域的颜色,使其看起来更加均匀一致。像素蛋糕软件提供了AI肤色统一和传统肤色统一两种功能,分别适用于不同需求。传统肤色统一算法通过皮肤分割、人脸检测、亮度统一和颜色统一等步骤,实现了对皮肤区域的精细调整。文章还提供了亮度统一的核心代码,并对比了传统算法与AI算法的效果,指出AI算法在自然度和亮度矫正方面表现更优。整体而言,本文为影楼精修中的肤色统一提供了实用的技术参考。

Trent1985的专栏 2065

TLS 线程局部存储

        在学习逆向的过程中,大家可能了解到利用TLS,可以实现反调试,因为TLS回调函数会在入口函数之前执行,但是可能不知道具体的原理,以及TLS是个什么东西,通过下面的介绍,你将会了解TLS的原理以及用法。 什么是线程局部存储?        线程局部存储(Thread Local Storage),又简称T...

z4ky的博客 1552

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

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

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

线程的局部存储

一、什么是线程的局部存储 在前面提到多线程或者多进程编程中,都会提到一个资源共享的问题。现在可以知道通过使用各种锁来控制数据的共同访问资源的问题。但在实际情况中还会有一种场景,就是每个线程都有自己的相同的类似的资源,这样每个线程都可以控制自己的资源。就如好多孩子一起捡豆子,每人有一个盛豆子的容器一样,每个孩子把自己的豆子放到自己的容器中去,最后凭谁的多来判断胜负。 线程局部存储的意思和上面的例子差不多,其实就是多个线程中的变量你是你的我是我的,咱们互不搭界,互不侵犯,最典型的就是VC中的Getlasterr

fpcc的专栏 1029

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

10.线程局部存储

对于一个存在多个线程的进程来说,有时候我们需要有一份数据是每个线程都拥有一份的,也就是说每个线程自己操作自己的这份数据,这有点类似 C++ 类的实例属性,每个实例对象操作的都是自己的属性。我们把这样的数据称之为。上述程序一共创建 5 个线程,每个线程都会自己生成一个日志文件,每个线程将自己的日志写入自己的文件中,当线程执行结束时,会关闭打开的日志文件句柄。是一个线程局部变量,因此该进程中每一个线程都会拥有这样一个变量副本,由于是不同的副本,)数据,因为进程中的所有线程都可以使用返回的键,所以参数。

左雪菲的专栏 1252

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Java 线程局部存储

一,简介和应用 Java中对线程局部存储进行支持的类是: public class ThreadLocal extends Object 其文档解释为: 该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其

IterZebra 4182

线程局部存储TLS

线程局部存储TLS堆栈中定义的局部变量,对多线程是安全的,因为不同的线程有自己的堆栈。而通常定义的全局变量,所有线程都可以作读写访问,这样它就不是线程安全的,为安全就有必要加锁互斥访问。而何为线程局部存储(TLS),简单的说,就是一个变量(通常是指针,指向具体的类型),每个线程都有一个副本,而在程序中可以按照相同的方式来访问,(比如使用相同的变量名,又或者都调用TlsGetValue),既然是

complex_ok的专栏 5018

线程局部存储(TLS)

(Thread Local Storage,TLS),是一种变量的存储方法,这个变量在它所在的线程内是全局可访问的,但是不能被其他线程访问到,这样就保持了数据的线程独立性。而熟知的全局变量,是所有线程都可以访问的,这样就不可避免需要锁来控制,增加了控制成本和代码复杂度。

yelvens的博客 2610

java线程局部存储_线程局部存储

线程局部存储线程局部存储(TLS) 是一种存储持续期(storage duration),对象的存储是在线程开始时分配,线程结束时回收,每个线程有该对象自己的实例。这种对象的链接性(linkage)可以是静态的也可是外部的。TLS的一个例子是用全局变量Windows的实现[编辑]每个进程都有一组标志,共TLS_MINIMUM_AVAILABLE(==64)个。每个标志可以被设为FREE或INUS...

weixin_39595164的博客 374

C++ 之线程局部存储

线程局部存储(TLS,thread local storage)是一个已有的概念。简单地说,所谓线程局部存储变量,就是拥有线程生命期及线程可见性的变量。 线程局部存储实际上是由 单线程程序中的全局/静态变量被应用到多线程程序中 被线程共享而来。 通常情况下,线程会拥有自己的栈空间,但是堆空间、静态数据区(如果从可执行文件的角度来看,静态数据区对应的是可执行文件的data、bss段的数据,而从C/C++语言层面而言,则对应的是全局/静态变量)则是共享的。这样一来,全局、静态变量在这种多线程模型下就总...

Peace 1576

Linux中的线程局部存储

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

每天写一点,进步一点点 595
上一篇: Unix调试工具dbx使用方法
下一篇: Window 8 体验
henrik_he
博客等级 码龄16年 36粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值