00. 目录

文章目录

  • 00. 目录
  • 01. 线程之间共享数据
  • 02. 线程私有数据
    • 2.1 创建线程私有数据
    • 2.2 销毁线程私有数据
    • 2.3 关联线程私有数据成员
    • 2.4 读取线程私有数据所关联的值
  • 03. 案例实践
  • 04. 附录

01. 线程之间共享数据

在多线程程序中,经常要用全局变量来实现多个函数间的数据共享。由于数据空间是共享的,因此全局变量也为所有线程共有。

测试代码:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>int key = 100; //全局变量void *helloworld_one(void *arg)
{printf("the message is %s\n",(char *)arg);key = 10;printf("key=%d, the child id is %lu\n", key, pthread_self());return NULL;
}void *helloworld_two(void *arg)
{printf("the message is %s\n", (char *)arg);sleep(1);printf("key=%d, the child id is %lu\n", key, pthread_self());return NULL;
}int main(int argc, char *argv[])
{pthread_t thread_id_one;pthread_t thread_id_two;//创建线程pthread_create(&thread_id_one, NULL, helloworld_one, "helloworld_one");pthread_create(&thread_id_two, NULL, helloworld_two, "helloworld_two");//等待线程结束,回收资源pthread_join(thread_id_one, NULL);pthread_join(thread_id_two, NULL);return 0;
}

测试结果:

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c -pthread
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out
the message is helloworld_one
key=10, the child id is 139954627110656
the message is helloworld_two
key=10, the child id is 139954618717952
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$

由运行结果可以看出,其中一个线程对全局变量的修改将影响到另一个线程的访问。

02. 线程私有数据

但有时应用程序设计中必要提供线程私有的全局变量,这个变量仅在线程中有效,但却可以跨过多个函数访问。比如在程序里可能需要每个线程维护一个链表,而会使用相同的函数来操作这个链表,最简单的方法就是使用同名而不同变量地址的线程相关数据结构。这样的数据结构可以由 Posix 线程库维护,成为线程私有数据 (Thread-specific Data,或称为 TSD)。

2.1 创建线程私有数据

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
功能:创建一个类型为 pthread_key_t 类型的私有数据变量( key )。
参数:key:在分配( malloc )线程私有数据之前,需要创建和线程私有数据相关联的键( key ),这个键的功能是获得对线程私有数据的访问权。destructor:清理函数名字( 如:fun )。当线程退出时,如果线程私有数据地址不是非 NULL,此函数会自动被调用。该函数指针可以设成 NULL ,这样系统将调用默认的清理函数。回调函数其定义如下:void fun(void *arg){// arg 为 key 值}
返回值:成功:0失败:非 0

不论哪个线程调用 pthread_key_create(),所创建的 key 都是所有线程可访问,但各个线程可根据自己的需要往 key 中填入不同的值,相当于提供了一个同名不同值的变量。

2.2 销毁线程私有数据

int pthread_key_delete(pthread_key_t key);
功能:注销线程私有数据。这个函数并不会检查当前是否有线程正使用线程私有数据( key ),也不会调用清理函数 destructor() ,而只是将线程私有数据( key )释放以供下一次调用pthread_key_create() 使用。
参数:key:待注销的私有数据。
返回值:成功:0失败:非 0

2.3 关联线程私有数据成员

int pthread_setspecific(pthread_key_t key, const void *value);
功能:设置线程私有数据( key ) 和 value 关联,注意,是 value 的值(不是所指的内容)和 key 相关联。
参数:key:线程私有数据。value:和 key 相关联的指针。
返回值:成功:0失败:非 0

2.4 读取线程私有数据所关联的值

void *pthread_getspecific(pthread_key_t key);
功能:读取线程私有数据( key )所关联的值。
参数:key:线程私有数据。
返回值:成功:线程私有数据( key )所关联的值。失败:NULL

03. 案例实践

测试程序

// this is the test code for pthread_key
#include <stdio.h>
#include <pthread.h> pthread_key_t key;   // 私有数据,全局变量void echomsg(void *t)
{ printf("[destructor] thread_id = %lu, param = %p\n", pthread_self(), t);
} void *child1(void *arg)
{ int i = 10;pthread_t tid = pthread_self(); //线程号printf("\nset key value %d in thread %lu\n", i, tid); pthread_setspecific(key, &i); // 设置私有数据printf("thread one sleep 2 until thread two finish\n\n");sleep(2); printf("\nthread %lu returns %d, add is %p\n",tid, *((int *)pthread_getspecific(key)), pthread_getspecific(key) );
} void *child2(void *arg)
{ int temp = 20;pthread_t tid = pthread_self();  //线程号printf("\nset key value %d in thread %lu\n", temp, tid); pthread_setspecific(key, &temp); //设置私有数据sleep(1); printf("thread %lu returns %d, add is %p\n", tid, *((int *)pthread_getspecific(key)), pthread_getspecific(key));
} int main(void)
{ pthread_t tid1,tid2; pthread_key_create(&key, echomsg); // 创建pthread_create(&tid1, NULL, child1, NULL); pthread_create(&tid2, NULL, child2, NULL); pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_key_delete(key); // 注销return 0;
}

执行结果:

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out  set key value 10 in thread 140551366268672set key value 20 in thread 140551357875968
thread one sleep 2 until thread two finishthread 140551357875968 returns 20, add is 0x7fd4a9c23ecc
[destructor] thread_id = 140551357875968, param = 0x7fd4a9c23eccthread 140551366268672 returns 10, add is 0x7fd4aa424ecc
[destructor] thread_id = 140551366268672, param = 0x7fd4aa424ecc
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$

从运行结果来看,各线程对自己的私有数据操作互不影响。也就是说,虽然 key 是同名且全局,但访问的内存空间并不是同一个。

04. 附录

【Linux系统编程】线程私有数据相关推荐

  1. Linux系统编程——线程私有数据

    在多线程程序中.常常要用全局变量来实现多个函数间的数据共享.因为数据空间是共享的,因此全局变量也为全部线程共同拥有. 測试代码例如以下: #include <stdio.h> #inclu ...

  2. Linux系统编程——线程(1)

    目录 线程概要 Linux内核线程实现原理 线程的共享/不共享资源 线程优缺点 线程控制原语 pthread_self pthread_create pthread_exit pthread_join ...

  3. Linux系统编程——线程

    一.线程概念 基础 线程又称LWP:light weight process 轻量级的进程,(在linux环境下)本质仍是进程.进程:独立地址空间,拥有PCB 线程:有独立的PCB,但没有独立的地址空 ...

  4. Linux系统编程——线程池

    http://blog.csdn.net/tennysonsky/article/details/46490099# 线程池基本原理 在传统服务器结构中,常是有一个总的监听线程监听有没有新的用户连接服 ...

  5. 入门Linux系统编程--网络编程

    文章目录 一.网络编程 1.socket服务端代码实现(无连接客户端) 6.socket服务端代码实现(连接客户端) 7.socket客户端代码实现 8.实现双方聊天 9.多方消息收发 二.往期文章 ...

  6. linux服务器开发二(系统编程)--线程相关

    线程概念 什么是线程 LWP:Light Weight Process,轻量级的进程,本质仍是进程(在Linux环境下). 进程:独立地址空间,拥有PCB. 线程:也有PCB,但没有独立的地址空间(共 ...

  7. linux线程并不真正并行,Linux系统编程学习札记(十二)线程1

    Linux系统编程学习笔记(十二)线程1 线程1: 线程和进程类似,但是线程之间能够共享更多的信息.一个进程中的所有线程可以共享进程文件描述符和内存. 有了多线程控制,我们可以把我们的程序设计成为在一 ...

  8. Linux系统编程(八)线程

    Linux系统编程(八)线程 一.什么是线程? 二.Linux内核线程实现原理 线程共享资源 线程非共享资源 线程优缺点 线程控制原语 一.什么是线程? LWP:light weight proces ...

  9. 【Linux | 系统编程】Linux系统编程(文件、进程线程、进程间通信)

    文章目录 Linux系统编程 文件IO open/close函数 read/write函数 文件描述符 阻塞.非阻塞 fcntl函数 lseek函数 传入传出参数 文件系统 文件存储 文件操作 sta ...

最新文章

  1. 2022-2028年中国半导体硅片行业深度调研及投资前景预测报告
  2. 计算机专业大一暑假,2020年计算机专业大学生暑期社会实践调查报告
  3. 使用频繁的正则表达式集合
  4. Linux epoll的用法
  5. 基于SpringBoot+webSocket实现扫码登录功能
  6. 数据结构(线性表)——神奇的幻方
  7. VPC2007与VServer2005R2比较
  8. 深度学习:batch_size和学习率 及如何调整
  9. php if多条件_通过PHP与Python代码对比浅析语法差异
  10. 双系统、多系统快速切换
  11. Servlet 中的四大作用域
  12. Linux创建用户密码修改
  13. OpenCV - Universal intrinsics 统一指令集
  14. Python基础 | Spyder的使用
  15. pol点获取及火星坐标系转换
  16. 共识协议(7)aura
  17. 计算机图形图像处理应用分析,计算机图形图像处理相关技术应用分析
  18. printk在应用层的设置方式及读取内核打印信息的方法
  19. wpf教程-环境搭建
  20. 挂耳式运动耳机哪个品牌好?挂耳式骨传导运动耳机推荐

热门文章

  1. 关于ssh的一些问题
  2. 解决datagrid单元格不能设置100%问题
  3. ArcGIS下的多节点可达性分析
  4. 设计数据层组件并在层间传递数据
  5. c语言学习之用筛选法求100之内的素数。
  6. GCDWebUploader支持iOS进入后台后仍然可以进行传输
  7. 年报统计系统—基本信息模块的目标文档
  8. 【知了堂学习笔记】java 编写几种常见排序算法3
  9. Hadoop 运行jar包时 java.lang.ClassNotFoundException: Class com.zhen.mr.RunJob$HotMapper not found...
  10. Unreal Engine 4 —— 冷却UI的制作