千家信息网

线程局部变量使用与多线程开发的示例分析

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章主要为大家展示了"线程局部变量使用与多线程开发的示例分析",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"线程局部变量使用与多线程开发的示例分析"这篇
千家信息网最后更新 2026年11月02日线程局部变量使用与多线程开发的示例分析

这篇文章主要为大家展示了"线程局部变量使用与多线程开发的示例分析",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"线程局部变量使用与多线程开发的示例分析"这篇文章吧。

一、概述

现在多核时代多线程开发越来越重要了,多线程相比于多进程有诸多优势(当然也有诸多劣势)。在早期C的库中,有许多函数是线程不安全的,因为内部用到了静态变量,比如:char *strtok(char *s, const char *delim); 该函数内部就有一个静态指针,如果多个线程同时调用此函数时,可能就会出现奇怪的结果,当然也不是我们所想要的,现在LINUX对此函数功能有一个线程安全版本的接口:char *strtok_r(char *s, const char *delim, char **ptrptr),这就避免了多个线程同时访问的冲突问题。其实,如果保持 strtok()/2 接口不变,同时还要保证线程安全,还有一个解决办法,那就是采用线程局部变量。

使用线程局部变量有两种使用方式,一个稍微麻烦些,一个比较简单,下面一一做个介绍(以LINUX为例)

二、线程局部变量的使用

比较麻烦些的使用方法用到的函数主要有三个:pthread_once(pthread_once_t*, void (*init_routine)(void)), pthread_key_create()/2, pthread_setspecific()/2, pthread_getspecific()/1,其中 pthread_once 可以保证在整个进程空间init_routine函数仅被调用一次(它解决了多线程环境中使得互斥量和初始化代码都仅被初始化一次的问题);pthread_key_create 的参数之一指一个析构函数指针,当某个线程终止时该析构函数将被调用,并用对于一个进程内的给定键,该函数只能被调用一次;pthread_sespecific 和 pthread_getspecific 用来存放和获取与一个键关联的值。例子如下:

pthread_key_t key;  pthread_once_t once = PTHREAD_ONCE_INIT;   static void destructor(void *ptr)  {  free(ptr);  }   void init_once(void)  {  pthread_key_create(&key, destructor);  }   static void *get_buf(void)  {  pthread_once(&once, init_once);   if ((ptr = pthread_getspecific(key)) == NULL) {  ptr = malloc(1024);  pthread_setspecific(key, ptr);  }  return (ptr);  }   static void *thread_fn(void *arg)  {  char *ptr = (char*) get_buf();   sprintf(ptr, "hello world");  printf(">>%s\n", ptr);  return (NULL);  }   void test(void)  {  int   i, n = 10;  pthread_t tids[10];   for (i = 0; i < n; i++) {  pthread_create(&tids[i], NULL, thread_fn, NULL);  }   for (i = 0; i < n; i++) {  pthread_join(&tids[i], NULL);  }  }

另外,还有一个更加简单使用线程局部变量的方法:__thread 修饰符, (在WIN32平台下需要用: __declspec(thread) 修饰符,WIN32的东东总得要多写几笔,呵呵),于是上述代码可以修改如下:

static void *get_buf(void)  {  static __thread void *ptr = malloc(1024);  return (ptr);  }   static void *thread_fn(void *arg)  {  char *ptr = (char*) get_buf();   sprintf(ptr, "hello world");  printf(">>%s\n", ptr);  return (NULL);  }   void test(void)  {  int   i, n = 10;  pthread_t tids[10];   for (i = 0; i < n; i++) {  pthread_create(&tids[i], NULL, thread_fn, NULL);  }   for (i = 0; i < n; i++) {  pthread_join(&tids[i], NULL);  }  }

看到没有,这段代码比前面一个简单许多,但却有一个问题,它存在内存泄露问题,因为当线程退出时各个线程分配的动态内存(ptr = malloc(1024)) 并没有被释放。

三、用ACL线程接口操作线程局部变量

为了解决上述问题,ACL库中实现了线程局部变量的简单释放功能:acl_pthread_atexit_add(void *arg, void (*free_callback)(void*)),修改上述代码如下:

static void free_fn(void *ptr)  {  free(ptr);  }   static void *get_buf(void)  {  static __thread void *ptr = malloc(1024);   acl_pthread_atexit_add(ptr, free_fn);  return (ptr);  }   static void *thread_fn(void *arg)  {  char *ptr = (char*) get_buf();   sprintf(ptr, "hello world");  printf(">>%s\n", ptr);  return (NULL);  }   void test(void)  {  int   i, n = 10;  pthread_t tids[10];   for (i = 0; i < n; i++) {  acl_pthread_create(&tids[i], NULL, thread_fn, NULL);  }   for (i = 0; i < n; i++) {  acl_pthread_join(&tids[i], NULL);  }  }

ok, 一切问题得到解决。细心的读者会发现 pthread_create, pthread_join 前面都加了前缀: acl_, 这是因为 ACL库对线程库进行了封装,以适应不同平台下(UNIX、WIN32)下的使用,这个例子是跨平台的,WIN32下同样可用。

以上是"线程局部变量使用与多线程开发的示例分析"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

线程 变量 局部 函数 问题 开发 代码 示例 分析 安全 内容 同时 接口 篇文章 进程 例子 内存 功能 多个 平台 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技企业 亿人帮互联网科技有限公司 智能科技公司是互联网公司吗 互联网 视角下的科技创新 互联网金融科技委员会 天扬科技互联网广告 新华互联网科技校企合作 互联网和高科技公司 云创客互联网科技公司 现代科技和互联网有关系吗 南平创想时代互联网科技有限公司 宝灵互联网科技有限公司 湖南一路畅行互联网科技 西安小鹰速贷互联网科技有限公司 下一代互联网重大应用科技园 抖集互联网科技技术咨询 互联网金融运营模式中的金融科技 亚光科技低轨卫星互联网 10位科技互联网大佬 武汉亿视互联网科技有限公司 科技创新与互联网经济 互联网是不是新科技 互联网与未来科技 西安互联网科技公司 云创客互联网科技公司 互联网科技和法律行业 互联网科技如何创业 2021互联网科技公司排名 图游互联网科技 抖集互联网科技技术咨询
0