线程特定数据(学习)

1、首先,为什么要使用线程特定数据呢?什么是线程特定数据。这牵涉到重入函数和不可重入函数。

重入函数就是在多个进程或者线程中,可以同时进行运行的函数,可重入函数就是不可以同时运行的函数,这个主要是可能多个进程或线程共享了一个变量,这个变量只有一个,这样同时运行的时候,就会出问题了,因为我们不知道这个静态变量具体是存入的什么值,可能刚存入一个值,立马又因为调用这个函数编程另外一个值。更加通俗的说,

在函数体内不访问那些全局变量,不使用静态局部变量,坚持只使用局部变量,写出的函数就将是可重入的。如果必须访问全局变量,记住利用互斥信号量来保护全局变量。


好了,说了这么多,如果多个线程同时访问一个函数,而这个函数恰好也必须使用一个静态变量,那么,线程特定数据就是来解决这个问题的。


2、每一个系统支持的线程特定数据元素限制不一样。POSIX要求这个限制不小于128(每一格进程)。系统为每一个进程维护一个称之为Key结构的结构数组。如图1

线程特定数据(学习)_第1张图片

Key结构中额标志指示这个数组元素是否正在使用。当一个线程调用进程创建函数pthread_key_create时候,系统搜索该进程的Key结构数组找到第一个不使用的的元素,该元素的索引称之为键,返回给调用线程的正是这个索引。

除了进程范围内的Key结构数组外,系统还在进程内维护关于每一个线程的多条信息。这些特定于线程的信息我们称之为Pthread结构,如图2

线程特定数据(学习)_第2张图片

pthread结构与Key结构是一一对应的。当创建一个线程的时候,系统会根据Key结构搜索,得到一个返回值,也就是Key结构的索引,每一个线程可以为该键值存储一个值(指针)。这个指针通常是通过malloc获取的。如图3。这样,当一个函数有一个静态变量的时候,多个线程同时访问,因为这个静态变量存放在键值中,就不会存在一个线程将另外一个线程的值覆盖的情况了。

线程特定数据(学习)_第3张图片

因为是malloc分配的实际数据空间,所以在线程结束的时候一定注意了,要释放空间。这个可以在析构函数中进行。


线程特定函数的典型用法如下:

pthread_key_t r1_key;
pthread_once_t re_once = PTHREAD_ONCE_INIT;
//定义析构函数,释放空间
void readline_destructor(void *ptr)
{
    free(ptr);
}
//初始化函数
 void readline_once(void)
{
   pthread_key_create(&r1_key,readline_destructor);
}

ssize_t
readline(...)
{
  ....
  pthread_once(&r1_once,readline);
  if((ptr = pthread_getspecific(r1_key)) == NULL)
   {
      ptr = malloc(....);
      //设置键值对。
      pthread_setspecific(r1_key,ptr);
       ....
    }
     .....
    
}

每一次readline被调用的时候,它都调用pthread_once,根据r1_once的值(PTHREAD_ONCE_INIT),readline这个函数值被调用了一次。pthread_getspecific()获取相应的特定线程数据,pthread_setspecific()设置特定线程数据。

重新复习一次。以此为证。

你可能感兴趣的:(线程特定数据)