4. 线程本地存储

内线程之间可以共享内存地址空间,线程之间的数据交换可以非常快捷,这是线程最显著的优点。但是多个线程访问共享数据,需要昂贵的同步开销,也容易造成与同步相关的BUG,更麻烦的是有些数据根本就不希望被共享,这又是缺点。可谓:“成也萧何,败也萧何”,说的就是这个道理。

C程序库中的errno是个最典型的一个例子。errno是一个全局变量,会保存最后一个系统调用的错误代码。在单线程环境并不会出现什么问题。但是在多线程环境,由于所有线程都会有可能修改errno,这就很难确定errno代表的到底是哪个系统调用的错误代码了。这就是有名的“非线程安全(Non Thread-Safe)”的。

此外,从现代技术角度看,在很多时候使用多线程的目的并不是为了对共享数据进行并行处理(在Linux下有更好的方案,后面会介绍)。更多是由于多核心CPU技术的引入,为了充分利用CPU资源而进行并行运算(不互相干扰)。换句话说,大多数情况下每个线程只会关心自己的数据而不需要与别人同步。

为了解决这些问题,可以有很多种方案。比如使用不同名称的全局变量。但是像errno这种名称已经固定了的全局变量就没办法了。在前面的内容中提到在线程堆栈中分配局部变量是不在线程间共享的。但是它有一个弊病,就是线程内部的其它函数很难访问到。目前解决这个问题的简便易行的方案是线程本地存储,即Thread Local Storage,简称TLS。利用TLS,errno所反映的就是本线程内最后一个系统调用的错误代码了,也就是线程安全的了。

Linux提供了对TLS的完整支持,通过下面这些接口来实现:

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);

pthread_key_create()接口用于创建一个线程本地存储区。第一个参数用来返回这个存储区的句柄,需要使用一个全局变量保存,以便所有线程都能访问到。第二个参数是线程本地数据的回收函数指针,如果希望自己控制线程本地数据的生命周期,这个参数可以传递NULL。

pthread_key_delete()接口用于回收线程本地存储区。其唯一的参数就要回收的存储区的句柄。

pthread_getspecific()和pthread_setspecific()这个两个接口分别用于获取和设置线程本地存储区的数据。这两个接口在不同的线程下会有不同的结果不同(相同的线程下就会有相同的结果),这也就是线程本地存储的关键所在。

代码5展示了如何在Linux使用线程本地存储,注意执行结果,分析一下线程本地存储的一些特性,以及内存回收的时机。

#include

#include

#include

#define THREAD_COUNT 10

pthread_key_t g_key;

typedef struct thread_data{

int thread_no;

} thread_data_t;

void show_thread_data()

{

thread_data_t *data = pthread_getspecific( g_key );

printf( "Thread %d \n", data->thread_no );

}

void* thread( void *arg )

{

thread_data_t *data = (thread_data_t *)arg;

printf( "Start thread %d\n", data->thread_no );

pthread_setspecific( g_key, data );

show_thread_data();

printf( "Thread %d exit\n", data->thread_no );

}

void free_thread_data( void *arg )

{

thread_data_t *data = (thread_data_t*)arg;

printf( "Free thread %d data\n", data->thread_no );

free( data );

}

int main( int argc, char *argv[] )

{

int i;

pthread_t pth[THREAD_COUNT];

thread_data_t *data = NULL;

pthread_key_create( &g_key, free_thread_data );

for( i = 0; i < THREAD_COUNT; ++i ) {

data = malloc( sizeof( thread_data_t ) );

data->thread_no = i;

pthread_create( &pth[i], NULL, thread, data );

}

for( i = 0; i < THREAD_COUNT; ++i )

pthread_join( pth[i], NULL );

pthread_key_delete( g_key );

return 0;

}

代码5使用线程本地存储

linux已使用线程,在Linux中使用线程相关推荐

  1. python 在主线程开线程_Python开启线程,在函数中开线程的实例

    逻辑处理上分成了多个模块,为了提高效率,前一个模块处理完调用后一个模块操作时使用多线程 我这里遇到的情形是前面取数据后面存到mysql,发现单线程效率很低,改为取数据后开线程存到mysql 开启线程之 ...

  2. python可以开多少线程_Python开启线程,在函数中开线程的实例

    逻辑处理上分成了多个模块,为了提高效率,前一个模块处理完调用后一个模块操作时使用多线程 我这里遇到的情形是前面取数据后面存到mysql,发现单线程效率很低,改为取数据后开线程存到mysql 开启线程之 ...

  3. java线程和内核线程的,Java中内核线程理论及实例详解

    1.概念 内核线程是直接由操作系统内核控制的,内核通过调度器来完成内核线程的调度并负责将其映射到处理器上执行.内核态下的线程执行速度理论上是最高的,但是用户不会直接操作内核线程,而是通过内核线程的接口 ...

  4. java多线程 线程安全_Java中的线程安全

    java多线程 线程安全 Thread Safety in Java is a very important topic. Java provides multi-threaded environme ...

  5. 操作系统中的进程与线程和java中的线程

    简介 在传统的操作系统中,进程拥有独立的内存地址空间和一个用于控制的线程.但是,现在的情况更多的情况下要求在同一地址空间下拥有多个线程并发执行.因此线程被引入操作系统. 为什么需要线程? 如果非要说是 ...

  6. java线程和操作系统线程_操作系统中的线程

    java线程和操作系统线程 线程数 (Threads) A thread is a unit of CPU utilization, which comprises the following par ...

  7. java 守护线程 作用_java中守护线程的一些概念和用法

    网上的资料中,守护线程的功能一般都是"只要当前JVM实例中尚存任何一个非守护线程没有结束,守护线程就全部工作:只有当最后一个非守护线程结束是,守护线程随着JVM一同结束工作,Daemon作用 ...

  8. java 全局变量线程安全_Java中的线程安全全局变量

    我试图了解 java中的线程安全机制,我需要一些帮助.我上课了: public class ThreadSafe { private Executor executor = new Scheduled ...

  9. android状态机是线程么,Java中的线程状态机 - java

    有没有一种方法可以将线程保留在状态中等待更改? 我的意思是,等一下事情发生了(更改var,调用方法等). 也许它需要使用事件监听器或同步的对象/方法. 这样的状态机通常的方法 statemachine ...

  10. linux+kill+进程和线程,在LINUX系统中 关于进程和线程终止的问题

    #include #include pthread_t thread; void *fun(void *arg) { printf("hell0n"); pthread_exit( ...

最新文章

  1. LabVIEW保存、读取配置文件
  2. 深入理解ROS技术 【4】ROS下的模块详解(181-232)
  3. [Leetcode] 445. Add Two Numbers II
  4. Pmcaff祝各位圣诞节快乐!
  5. [CQOI2009]叶子的染色
  6. Mybatis insert返回主键ID
  7. 2018年的AI/ML惊喜及预测19年的走势(一)
  8. Python获取主机信息、开机时间和开机时长、当前登陆用户
  9. GPS/BDS:LAC区域码和CELLID移动基站ID
  10. 【每日算法Day 109】五大解法,带你深入了解完全背包方案数
  11. 系列文章--WF学习资料汇总
  12. Python输入一个三位数,输出其个位数字、十位数字和百位数字。
  13. 异步编程不会?我教你啊!CompletableFuture(JDK1.8)
  14. maikr博客备份工具 3.0.0.0 详细介绍
  15. python读取plt文件吗_如何读取连续的.plt文件并存储它们
  16. IDEA牛逼!900行又臭又长的类重构,几分钟搞定
  17. Gartner发布《2021年企业低代码平台魔力象限》低码一体化平台成趋势
  18. Apache+php的安装和配置
  19. 大卫 异星觉醒 机器人_异星觉醒结局翻转恶心到观众?隐藏剧情暗含深意
  20. 物研究所做一位科研人员

热门文章

  1. AI 实战:GPS实景识别网络项目(源码共享)
  2. 腾讯云 AI 在新基建领域下一盘什么大棋
  3. 为什么有人月薪5000,还要选它:逆袭都发生在这儿
  4. 流行于机器学习竞赛的Boosting,一文讲透足够了
  5. 漫话:是时候说说到底什么是 IPv4 和 IPv6 了!
  6. 网易回应裁撤生病员工;苹果押宝 5G 手机;IntelliJ IDEA 2019.3 RC 发布 | 极客头条...
  7. 2020 年,开启现代库的基建学习 —— 从项目演进看前端工程化发展
  8. ofo 悄然搬离中关村;董明珠称向雷军学互联网营销;Chrome 77 发布 | 极客头条...
  9. Mate 30 不预装任何谷歌应用;阿里巴巴发布新“六脉神剑”;VS Code 1.38 发布 | 极客头条...
  10. 不止鸿蒙 OS,华为的备用操作系统还有“极光”?