线程私有数据

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

测试代码如下:

[cpp] view
plain
copy

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <unistd.h>
  4. #include <stdlib.h>
  5. int key = 100; //全局变量
  6. void *helloworld_one(void *arg)
  7. {
  8. printf("the message is %s\n",(char *)arg);
  9. key = 10;
  10. printf("key=%d, the child id is %lu\n", key, pthread_self());
  11. return NULL;
  12. }
  13. void *helloworld_two(void *arg)
  14. {
  15. printf("the message is %s\n", (char *)arg);
  16. sleep(1);
  17. printf("key=%d, the child id is %lu\n", key, pthread_self());
  18. return NULL;
  19. }
  20. int main(int argc, char *argv[])
  21. {
  22. pthread_t thread_id_one;
  23. pthread_t thread_id_two;
  24. //创建线程
  25. pthread_create(&thread_id_one, NULL, helloworld_one, "helloworld_one");
  26. pthread_create(&thread_id_two, NULL, helloworld_two, "helloworld_two");
  27. //等待线程结束,回收资源
  28. pthread_join(thread_id_one, NULL);
  29. pthread_join(thread_id_two, NULL);
  30. return 0;
  31. }

运行结果如下:

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

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

下面接口所需头文件:

#include <pthread.h>

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)注销线程私有数据

int pthread_key_delete(pthread_key_t key);

功能:

注销线程私有数据。这个函数并不会检查当前是否有线程正使用线程私有数据( key ),也不会调用清理函数 destructor() ,而只是将线程私有数据( key )释放以供下一次调用 pthread_key_create() 使用。

参数:

key:待注销的私有数据。

返回值:

成功:0

失败:非 0

3)设置线程私有数据的关联

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

功能:

设置线程私有数据( key ) 和 value 关联,注意,是 value 的值(不是所指的内容)和 key 相关联。

参数:

key:线程私有数据。

value:和 key 相关联的指针。

返回值:

成功:0

失败:非 0

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

void *pthread_getspecific(pthread_key_t key);

功能:

读取线程私有数据( key )所关联的值。

参数:

key:线程私有数据。

返回值:

成功:线程私有数据( key )所关联的值。

失败:NULL

示例代码如下:

[cpp] view
plain
copy

  1. // this is the test code for pthread_key
  2. #include <stdio.h>
  3. #include <pthread.h>
  4. pthread_key_t key;  // 私有数据,全局变量
  5. void echomsg(void *t)
  6. {
  7. printf("[destructor] thread_id = %lu, param = %p\n", pthread_self(), t);
  8. }
  9. void *child1(void *arg)
  10. {
  11. int i = 10;
  12. pthread_t tid = pthread_self(); //线程号
  13. printf("\nset key value %d in thread %lu\n", i, tid);
  14. pthread_setspecific(key, &i); // 设置私有数据
  15. printf("thread one sleep 2 until thread two finish\n\n");
  16. sleep(2);
  17. printf("\nthread %lu returns %d, add is %p\n",
  18. tid, *((int *)pthread_getspecific(key)), pthread_getspecific(key) );
  19. }
  20. void *child2(void *arg)
  21. {
  22. int temp = 20;
  23. pthread_t tid = pthread_self();  //线程号
  24. printf("\nset key value %d in thread %lu\n", temp, tid);
  25. pthread_setspecific(key, &temp); //设置私有数据
  26. sleep(1);
  27. printf("thread %lu returns %d, add is %p\n",
  28. tid, *((int *)pthread_getspecific(key)), pthread_getspecific(key));
  29. }
  30. int main(void)
  31. {
  32. pthread_t tid1,tid2;
  33. pthread_key_create(&key, echomsg); // 创建
  34. pthread_create(&tid1, NULL, child1, NULL);
  35. pthread_create(&tid2, NULL, child2, NULL);
  36. pthread_join(tid1, NULL);
  37. pthread_join(tid2, NULL);
  38. pthread_key_delete(key); // 注销
  39. return 0;
  40. }

运行结果如下:

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

本教程示例代码下载请点此处。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 03:37:58

线程私有数据的相关文章

12.6 线程私有数据

线程私有数据是一种用于存储和获取与特定线程相关联数据的机制,称为线程特定的或者是线程私有的,是因为我们希望每个线程都可以独立访问其独有的数据,而不用担心与其他线程的同步访问问题. 许多人费力实现了促进进程数据以及属性贡献的线程模型,那么为什么还有人想要实现一个接口,在这样一个模型中防止共享呢?有如下两点原因: 首先,有些时候我们需要以线程为基础维护一些数据,因为没有任何机制可以保证线程ID总是比较小的,且是连续的整数,因此我们不能简单地将每一个线程的私有数据分配为一个数组,然后使用线程ID作为索

SylixOS线程私有数据浅析

目录 1. 线程私有数据概述    1 2. 线程私有数据的相关API函数流程浅析    1 2.1    加入线程私有变量    1 2.2    删除线程私有变量    3 2.3    设置私有线程变量    6 2.4    获得线程私有变量值    8 3. 总结    10 4. 参考文献    10 线程私有数据概述 在SylixOS中为了满足多线程安全的要求,使得一种资源可以安全的被多个线程使用,采用了包括代码临界区保护和可重入性等方法.本文描述实现可重入的一种方法:线程私有数据

【C/C++多线程编程之十】pthread线程私有数据

多线程编程之线程私有数据 Pthread是 POSIX threads 的简称,是POSIX的线程标准.  线程同步从互斥量[C/C++多线程编程之六]pthread互斥量,信号量[C/C++多线程编程之七]pthread信号量,条件变量[C/C++多线程编程之八]pthread条件变量,读写锁[C/C++多线程编程之九]pthread读写锁,多线程的同步机制已经有了清晰深入的探究,多线程编程的精髓所在,需要深入理解.        线程私有数据TSD(Thread-specific Data)

pthread_getspecific()--读线程私有数据|pthread_setspecific()--写线程私有数据

原型: #include <pthread.h> void *pthread_getspecific(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *value); 说明: TSD 的读写都通过上面两个专门的 Posix Thread 函数进行. 函数 pthread_setspecific() 将 pointer 的值 (不是锁指的内容) 与key 相关联. 函数 pthread_getsp

posix多线程--线程私有数据

1.当多个线程共享一个变量时,将该变量定义为静态或外部变量,使用互斥量确保共享变量的安全访问.如果每个线程都需要一个私有变量值,则该值成为线程的私有数据.程序创建一个键,每个线程独立地设定或得到自己的键值,各线程间私有数据互不影响. 2.建立线程私有数据int pthread_key_create(pthread_key_t *key,void (*destructor)(void *));int pthread_key_delete(pthread_key_t key);int pthread

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

在多线程程序中,经常要用全局变量来实现多个函数间的数据共享.由于数据空间是共享的,因此全局变量也为所有线程共有. 测试代码如下: #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

线程私有数据和pthread_once

#include <stdio.h> #include <pthread.h> pthread_key_t key; pthread_once_t ponce = PTHREAD_ONCE_INIT; void ronce(){ printf("%s\n", "ronce"); } void *thread1(){ pthread_setspecific(key, "thread1"); printf("%s\n

操作线程私有数据的函数主要有4个:

在线程内部,线程私有数据可以被各个函数访问到,但它对其他线程是屏蔽的. 使用线程数据时,首先要为每个线程数据创建一个相关联的键.在各个线程内部,都使用这个公用的键来指代线程数据,但是在不同的线程中,这个键代表的数据是不同的.也就是说,key一旦被创建,所有线程都可以访问它,但各线程可根据自己的需要往key中填入不同的值.这相当于提供了一个同名而不同值的全局变量,一键多值. 操作线程私有数据的函数主要有4个:pthread_key_create(创建一个键)pthread_setspecific(

JVM线程私有数据区

本章节内容参考:<深入理解Java虚拟机> 运行时数据区: 本章节只介绍线程私有的内存模型. 虚拟机栈(FILO):java方法执行的内存模型. 栈帧(线程执行的一个方法的内存模型,每调用一个方法,压入一个栈帧) 局部变量表:编译器可知的8种基本类型.reference类型.returnAddress类型 操作数栈:一个用于计算的临时数据存储区(明显,此栈是为了存放要操作的数据用的) 动态链接:支持java多态 返回地址:方法结束的地方.return/Exception 本地方法栈:Nativ