线程这一章,着实不好理解,写上一篇博客时,我还没这么想,
今天做了几道关于线程的题,觉得还是不行呀,还是乖乖再来一遍吧。
- 私有数据:
- 线程同步
1、私有数据
为什么要有线程私有数据呢?
我们知道在多线程环境下,进程内的所有线程共享进程的数据空间,所以全局变量为所有线程共有,但是在程序设计的时候有时需要保存线程自己的全局变量,例如:变量errno:返回标准的错误码,errno不应该是一个局部变量,因为每个函数几乎都可以访问它,但它又不能作为一个全局变量,否则在一个线程里输出的可能是另一个线程的出错信息,那么,这种问题就可以通过创建线程的私有数据来解决。
线程私有数据:可以被此线程内的各个函数访问,但对其他线程是屏蔽的。
采用一键多值的技术,即一个键对应多个数值。
操作线程私有数据的函数主要有四个:
(1)第一个
int pthread_key_create(pthread_key_t *key,void (*destr_function) (void *));
- 此函数用于创建一个键,参数key:指向键值的指针(这里是从Linux的TSD池中分配一项,将其值赋给key),第二个参数为一个函数指针,如果指针不为空,则在线程退出时将以key所关联的数据为参数调用destr_function(),释放分配的缓冲区。这里是从Linux的TSD池中分配一项,将其值赋给key,
key一旦被创建,所有的线程都可以访问它,但各线程可根据自己的需要往key中填入不同的值,就相当于提供了一个同名而不同值的全局变量,一键多值靠的是一个关键的数据结构数组,即TSD池。
即:
static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] ={
{
0,NULL}};
pthread_key_struct 结构体定义如下:
struct pthread_key_struct
{
uintptr_t seq;
void (*destr) (void *);
};
创建一个TSD,相当于将结构体数组的某一个元素的seq值设置为为“in_use”,并将其索引返回给*key,然后设置destr_function()为destr()。pthread_key_create创建一个新的线程私有数据key时,系统会搜索其所在进程的key结构数组,找出一个未使用的元素,将其索引赋给*key。
(2)第二个
作用:为一个键设置线程私有数据
int pthread_setspecific(pthread_key_t key, const void *pointer);
该函数将指针pointer的值(不是内容)与key相关联,用pthread_setspecific为一个键指定新的线程数据时,线程必须释放原有的数据用以回收空间。
(3)第三个
作用:从一个键读取线程私有数据
void * pthread_getspecific(pthread_key_t key);
通过该函数得到与key相关联的数据
(4)第四个
作用:删除一个键
void * pthread_getspecific(pthread_key_t key);
该函数用于删除一个键,删除后,键所占用的内存将被释放,但是与改key相关联的线程数据所占用的内存并不会被释放的,因此线程私有数据的释放必须在释放键之前。
下面为一个创建和使用线程私有数据的程序:
#include<stdio.h>
#include<unistd.h>
#include<string.h>