线程通信原理之一:线程本地存储(TLS)

线程本地存储(TLS)的学习 一、引言最近在看jemalloc的文章 A Scalable Concurrent malloc(3) Implementation for FreeBSD, 文中有提到,在分配Arena的时候用到了线程本地存储技术(thread-local storage),这里发散一下,复习一下什么是线程本地存储。二、简介Thread-local storage,也就是在多线程程序中,为每个线程提供该线程独占的 阅读详情

定义

Thread Local Storage (TLS) is the method by which each thread in a given multithreaded process can allocate locations in which to store thread-specific data. (https://msdn.microsoft.com/en-us/library/6yh4a9k1.aspx)。翻译过来,就是说一个TLS变量能在多个线程中保持相应的分身,每个线程能访问属于自己的那个分身,而对别的线程的分身无权访问(好像不是翻译。。。)。Android中的TLS类型的数据结构是ThreadLocal,它的实现就是用一个各线程共享的key-value映射数组,key是线程号,value是变量值,这样,每个线程就有对应的变量值了。 


Looper
Looper有一个静态的ThreadLocal类型的数据结构sThreadLocal,用来存储Looper对象。因为sThreadLocal是静态的,所以它为同一个进程中的所有的线程所共享。定义如下:
static final ThreadLocal<Looper> sThreadLocal = newThreadLocal<Looper>();
一个线程默认是没有自己的Looper的,它若想要使用Looper,需要在Thread的入口函数里面先调用Looper.prepare(),新创建一个Looper,并插入到sThreadLocal中,即在其中插入一个键值对;而Looper.myLooper()是拿属于自己这个线程的Looper,调用了sThreadLocal.get()。最后还需要调用Looper.loop()去循环处理mQueue中的消息。真正的处理需要调用msg.target.dispatchMessage,它是调用的这个Looper所位于的Handler内部的handlerMessage函数来处理消息。
final MessageQueue mQueue;
private static void prepare(boolean quitAllowed) {
sThreadLocal.set(new Looper(quitAllowed));
}
public static void loop() {
        final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
            Message msg = queue.next();
   msg.target.dispatchMessage(msg);
...
}
}
public static Looper myLooper() {
        return sThreadLocal.get();
    }
入口函数代码:
publicvoid run() {  
synchronized(mLock) {  
Looper.prepare();  
mLooper= Looper.myLooper();  
mLock.notifyAll();  
}  
Looper.loop();  

}


Handler
Handler是由某个线程创建的,但是由于线程共享进程空间,因此其他线程也可以访问到这个Handler。这是Handler起作用的基础。
在Handler的构造函数中
public Handler(Callback callback, boolean async) {
……
        mLooper = Looper.myLooper();
        mQueue = mLooper.mQueue;
……
    }
所以Handler是线程相关的,这个线程就是mLooper属于的线程,也是创造Handler的线程,也是Handler处理事情即调用handleMessage的线程。
向某个Handler发message需要调用sendMessage,最后会调到queue.enqueueMessage。向Handler发Runnable需要调用post。若handler是个Handler,那么handler.sendMessage(msg)就是往handler的queue里填充消息,其实就是给这个handler发消息。而handler.obtainMessage就是在消息池里拿消息,设置这个消息的target为handler。
题外话:
Handler中有个函数是runWithScissors,这个函数定义如下:
public final boolean runWithScissors(final Runnable r, long timeout) {
        if (Looper.myLooper() == mLooper) {
            r.run();
            return true;
        }
        BlockingRunnable br = new BlockingRunnable(r);
        return br.postAndWait(this, timeout);
}


怎么理解呢?看注释:
If the current thread is the same as the handler thread, then the runnable runs immediately without being enqueued.  Otherwise, posts the runnable to the handler and waits for it to complete before returning.
对照看代码,在当前线程和创建Handler的线程是一个线程的时候,直接运行runnable,否则,把runnable放入Handler的消息队列中,当前线程wait直到runnable运行完毕。


示例代码

1.	private static class Worker implementsRunnable {  
2.	        privatefinal Object mLock = new Object();  
3.	        privateLooper mLooper;  
4.	         
5.	        /** 
6.	         * Createsa worker thread with the given name. The thread 
7.	         * thenruns a {@link android.os.Looper}. 
8.	         * @paramname A name for the new thread 
9.	         */  
10.	        Worker(Stringname) {  
11.	            Threadt = new Thread(null, this, name);  
12.	           t.setPriority(Thread.MIN_PRIORITY);  
13.	           t.start();  
14.	            synchronized(mLock) {  
15.	                while(mLooper == null) {  
16.	                   try {  
17.	                       mLock.wait();  
18.	                   } catch (InterruptedException ex) {  
19.	                   }  
20.	                }  
21.	            }  
22.	        }  
23.	         
24.	        publicLooper getLooper() {  
25.	            returnmLooper;  
26.	        }  
27.	         
28.	        publicvoid run() {  
29.	            synchronized(mLock) {  
30.	               Looper.prepare();  
31.	                mLooper= Looper.myLooper();  
32.	                mLock.notifyAll();  
33.	            }  
34.	            Looper.loop();  
35.	        }  
36.	         
37.	        publicvoid quit() {  
38.	            mLooper.quit();  
39.	        }  
40.	    }  
41.	   
42.	   
43.	package com.example.test;  
44.	   
45.	import android.app.Activity;  
46.	import android.graphics.Bitmap;  
47.	import android.os.Bundle;  
48.	import android.os.Handler;  
49.	import android.os.Looper;  
50.	import android.os.Message;  
51.	import android.view.View;  
52.	import android.widget.ProgressBar;  
53.	import android.widget.TextView;  
54.	   
55.	public classProgressTestActivity extends Activity {  
56.	    privateProgressBar progress;  
57.	    private TextView text;  
58.	    private Worker mWorker;  
59.	    privateWorkerHandler mWorkerHandler;  
60.	    private UIHandlermUIHandler;  
61.	   
62.	    @Override  
63.	    public void onCreate(BundlesavedInstanceState) {  
64.	        super.onCreate(savedInstanceState);  
65.	        setContentView(R.layout.activity_main);  
66.	        progress =(ProgressBar) findViewById(R.id.progressBar1);  
67.	        text =(TextView) findViewById(R.id.textView1);  
68.	        mWorker = new Worker("artworker");  
69.	        mWorkerHandler = newWorkerHandler(mWorker.getLooper());  
70.	        mUIHandler = newUIHandler(Looper.myLooper());  
71.	    }  
72.	   
73.	    public voidstartProgress(View view) {  
74.	        Message msgObj = mWorkerHandler.obtainMessage();  
75.	        msgObj.what = 2;  
76.	        mWorkerHandler.sendMessage(msgObj);  
77.	    }  
78.	   
79.	    // Simulatingsomething timeconsuming  
80.	    private voiddoFakeWork() {  
81.	        try {  
82.	            Thread.sleep(1000);  
83.	        } catch(InterruptedException e) {  
84.	            e.printStackTrace();  
85.	        }  
86.	    }  
87.	   
88.	    private static class Worker implements Runnable{  
89.	        private final Object mLock = new Object();  
90.	        private Looper mLooper;  
91.	   
92.	        /** 
93.	         * Creates a worker thread with the given name.The thread then runs a 
94.	         * {@link android.os.Looper}. 
95.	         * 
96.	         * @param name 
97.	         *           A name for the new thread 
98.	         */  
99.	        Worker(String name) {  
100.	            Thread t = new Thread(null, this, name);  
101.	            t.setPriority(Thread.MIN_PRIORITY);  
102.	            t.start();  
103.	            synchronized (mLock) {  
104.	                while (mLooper == null) {  
105.	                    try {  
106.	                        mLock.wait();  
107.	                    } catch(InterruptedException ex) {  
108.	                    }  
109.	                }  
110.	            }  
111.	        }  
112.	   
113.	        public LoopergetLooper() {  
114.	            return mLooper;  
115.	        }  



C++的线程本地存储(Thread Local Storage) 在多线程环境中,全局变量和静态变量是所有线程共享的。这意味着,如果一个线程修改了一个全局变量或静态变量的值,那么其他线程将看到这个修改。这可能会导致数据竞争和其他并发问题。为了解决这个问题,我们可以使用线程本地存储。线程本地存储为每个线程提供了一份独立的数据副本。这样,每个线程都可以独立地操作自己的数据,而不会影响其他线程。线程本地存储是C++中处理并发问题的一个重要工具。通过使用线程本地存储,我们可以为每个线程提供一份独立的数据副本,这样每个线程都可以独立地操作自己的数据,而不会影响其他线程。 阅读详情

相关推荐

掌握多线程编程:使用线程局部存储TLS

本文还有配套的精品资源,点击获取 简介:线程局部存储(TLS)在多线程编程中用于实现数据隔离,让每个线程拥有独立的变量副本。C++中利用 thread_local 关键字实现,而在Windows平台下,VC++开发者可以通过 TlsAlloc 等API进行更底层的TLS管理。提供的示例项目涉及系统信息获取、线程同步和死锁问题、调度实验、多线程计算...

weixin_42153793的博客 2038

ThreadLocal简介

ThreadLocal简介

FourAu的博客 632

Android13 SurfaceFlinger启动流程分析

在Android13版本中,SurfaceFlinger是由Android.bp去启动init.rc文件,然后再解析文件去加载SurfaceFlinger。上面方法主要处理如下:1、调用surfaceflinger的createSurfaceFlinger方法,实例化surfaceflinger。2、调用flinger(surfaceflinger)的init()方法,在客户端连接之前进行初始化。

liuning1985622的博客 1919

线程本地存储TLS详解

博客的大部分原理转自:https://blog.youkuaiyun.com/zhangmiaoping23/article/details/44345341 本人自己把觉得自己需要的部分自己进行了综合。 TLS(Thread Local Storage)是为了多线程考虑其线程本身需要维持一些状态而设置的一种机制. TLS在概念上并不复杂。常规设计是将所有对TLS的访问都通过TEB中的指针来进行间接访问,TE...

For Geek 6475

FreeRTOS笔记(十五)FreeRTOS总结

文章目录01 - 裸机和FreeRTOS区别1.1 - 裸机1.2 - FreeRTOS1.3 - 区别02 - 对FreeRTOS的感受03 - 推荐 上一文链接:FreeRTOS笔记(十四)[简] 软件定时器、事件组、任务通知 01 - 裸机和FreeRTOS区别   学完FreeRTOS,应该要自己总结一下FreeRTOS和裸机的区别,宏观上说,FreeRTOS是一个运行在裸机上的微内核,...

单眼皮根号三的博客 4115

浊音/清音/爆破音的时域及频域特性

第一周作业 浊音/清音/爆破音的时域及频域特性 思路:使用Audacity进行录制,时域部分将音频放大观察波形规律,频域部分生成并进行频谱分析。 (1)浊音U 时域分析: 时域表现为短周期性,波形比较规律。 频域分析: 频域上表现为频率集中在低频区域,共振峰较为明显,短时能量较高。 (2)清音S 时域分析: 时域波形没有周期性,整体振幅小于浊音。 频域分析: 频域波形平缓,无共振峰,能量比较集中。 (3)爆破音t 时域分析: 脉冲波,更为尖锐,整体上振幅降低。 频域分析: 没有像浊音一样的共振

Leylaaaa的博客 1228

最后看一下什么是线程本地存储(TLS)

​线程本地存储又叫线程局部存储,英文名称为Thread Local Storage,简称TLS,实质上是线程私有的全局变量而已。 普通全局变量在多线程中是共享的,一个线程对其进行了修改,其它所有线程都可以看到,而线程私有的全局变量与普通全局变量不同,线程私有的全局变量是线程的私有财产,每个线程都有自己的一个副本,某个线程对其做出的修改只会修改到自己的副本,并不会修改到其它线程的副本。 来看个普通的全部变量的例子: #include <stdio.h>#include <pthrea

luyaran的博客 1419

RT-Thread与ROS2通信:micro-ROS在STM32上的移植实践

本文详细介绍了在STM32平台上使用RT-Thread实时操作系统移植micro-ROS实现与ROS2通信的实践方案。通过对比rosserial方案,重点阐述了micro-ROS基于XRCE-DDS协议栈在数据可靠性(丢包率低于1%)、双模式通信(UDP/串口)以及C/C++混合编程方面的优势,为嵌入式设备与ROS2的高效通信提供了完整解决方案。

emacs5lisp的博客 330

TLS--线程本地存储

线程局部存储(TLS),是一种变量的存储方法,这个变量在它所在的线程内是全局可访问的,但是不能被其他线程访问到,这样就保持了数据的线程独立性。

Nieweishan的博客 551

数据库小技能:数据导入脚本

背景:版本大升级,从2.0升级到3.0 ,服务端开发语言从c#换到java语言。数据库类型从microsalft sql server 换到mysql。数据来源于微信,用于查询卡bin。

专注于计算机研发知识和资讯分享 774

11、Windows Autopilot 部署与设备注册全攻略

本文详细介绍了Windows Autopilot的完整部署流程,涵盖注册配置文件设置、注册状态页面(ESP)配置、设备注册方法(包括CSV导入、JSON注入、在线注册等)、自动化脚本实现及故障排除技巧。通过手动与PowerShell自动化两种方式指导用户完成配置,并提供流程图、最佳实践和常见问题解答,帮助IT管理员高效实现设备零接触部署与管理。

ii567的博客 343

线程间通信原理

从操作系统的角度讲,线程间通信比进程间通信要容易的多,因为线程之间可以共享进程的内存空间。因此,他们可以共享位于进程全局数据区和栈和堆上的所有内容。 唯一只属于某个线程的就是线程的栈-------它可以存放只属于线程的对象。 下面逐一解读线程间通信方式: 1.   共享进程的变量 这是最基本的通信方式,但要注意不要共享线程栈上的变量,因为它随时可能被某个线程销毁,而另一个线程就无法访问它了

Walk More Slowly 1886

【代码版本管理】SVN(Subversion)

认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长!本文先对SVN(Subversion)代码版本管理做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章提示:以下是本篇文章正文内容。

qq_35635374的博客 668

线程本地存储TLS(Thread Local Storage)的原理和实现——分类和原理

线程本地存储TLS(Thread Local Storage)的原理和实现——分类和原理 本文为线程本地存储TLS系列之分类和原理。 一、TLS简述和分类 我们知道在一个进程中,所有线程是共享同一个地址空间的。所以,如果一个变量是全局的或者是静态的,那么所有线程访问的是同一份,如果某一个线程对其进行了修改,也就会影响到其他所有的线程。不过我们可能并不希望这样,所以更多的推荐用基于堆栈的自动变

chengfuyong001的专栏 1720

在 IW31 录入班次与当班负责人,并让 IW38 列表同步显示:基于 IWO10018 + IWOC0004 的一套可落地增强方案

摘要 本文详细介绍了在SAP PM模块中实现工厂设备维护订单增强的完整方案,重点解决两个核心需求:在订单创建时新增班次负责人和班次字段,并在订单列表中直接显示这些信息。文章从需求分析、技术设计到具体实现步骤进行了系统阐述。 关键实现步骤包括: 通过CI_AUFK结构扩展AUFK表,确保字段持久化存储 使用IWO10018增强在IW31/IW32/IW33事务中添加输入界面 通过IWOC0004增强在IW38订单列表中显示新增字段 采用优化的数据填充策略提升性能 该方案不仅满足业务需求,还考虑了用户体验和系统

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 176

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Android TLS

Android Linux的TLS(Thread Local Storage)实现由内核和用户两部分模块配合完成的。内核对TLS需要做的事情是能够让用户态程序在某个时刻能够设置线程唯一的基址值到内核的线程信息结构内。  用户态程序需要能在主线程运行时设置线程唯一的基址到内核。对于bionic的实现,是在动态链接器启动之前就要把主线程的struct pthread对象的基址使用上述的系统调用

4338

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

TLS (Thread local storage)

Thread local storage (TLS) enables multiple threads of the same process to use an index allocated by the TlsAlloc function to store and retrieve a value that is local to the thread. In this example, a

steel的专栏 853

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

基于线程本地存储(TLS)的三层内存池

一、TLS简介 在一个进程中,所有线程共享同一个地址空间。全局变量和静态变量能够被所有线程访问、修改。通过使用线程本地存储(Thread Local Storage,TLS)能够将数据和执行的特定线程联系起来。TLS是各线程独立的数据存储空间,声明的TLS变量在每个线程都有一个副本,在程序中可以安装相同方式来讨论,且互相不影响。 TLS分为静态的和动态的。静态TLS使用语言本身的关键字定义。C/C++中包括: 1、_thread 2、thread_local 3、_dec...

qq_44272681的博客 1087

线程本地存储(TLS)

TLS,全称thread local storage,一个进程的所有线程共享这个进程的虚拟地址空间,函数的局部变量,对于每个执行此函数的线程来说,都是唯一的。但是类的成员变量、静态变量、全局变量,对于线程来说是共享的(即每个线程都可以访问到)。①、进程内部有专门的数据结构来管理索引与lpvoid数据的对应关系,通过TlsAlloc()分配索引,通过TlsSetValue将索引与lpvoid关联起来,TlsGetValue(index)通过索引可以获取数据,TlsFree用来释放索引。

qq_17411797的博客 359

(二)线程------线程通信原理JMM模型

简述:     上一篇文章中我们学习了Java的内存模型,那么现在我们思考一个问题:如果程序中存在多个线程,他们是怎么进行数据通信的呢?OK,带着这个问题我们来学习本节内容---线程通信原理。     本篇博文主要讲解:      ① 什么是可见性、原子性、有序性。      ② JMM模型。 JMM简介:      JMM:Java Memory Model(Ja

lzy_tinyjoy 1356

线程局部存储(TLS)

线程局部存储,Part 1:概述 和其它主流多线程操作系统一样,Windows为大家提供一个机制,该机制允许程序员实现基于线程的局部状态存储。这种能力通常称为线程局部存储(Thread Local Storage,TLS),这对于那些需要保存线程相关信息但需要全局可见的应用场景非常有用。 尽管TLS的介绍有很好的文档可参考,但关于其实现细节的介绍并不多(尽管也有一些非官方文档进行比较表面的介绍)。 至少从高层来将,TLS在概念上并不复杂。常规设计是将所有对TLS的访问都通过TEB中的指针来进行间接访问

whl0071的专栏 2718

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

什么是线程本地存储(TLS,Thread Local Storage)呢?相信你看过很多次这个定义,但它表达的内涵是什么呢?本文从变量模型出发,讨论引入多线程编程模式之后,需要重新修改变量模型,从而引入TLS概念。

海枫的专栏 1万+

【C/C++】线程局部存储:原理与应用详解

是 C++11 引入的关键字,用于声明线程局部变量每个线程拥有该变量的独立副本,生命周期与线程绑定三种作用域:thread_local int x;// 全局 TLS 变量// 函数内 TLS 变量// 类静态 TLS 成员对比项全局变量变量访问速度快(直接寻址)慢(多级间接寻址)内存结构所有线程共享每线程独立并发安全性需加锁天然隔离应用场景跨线程共享数据每线程独立状态维护。

YZJincsdn的博客 1392
上一篇: Android多媒体:AudioTrack和AudioFlinger的交互
下一篇: 耳机插拔流程
我把葡萄酿成酒
博客等级 码龄12年 275粉丝 198原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值