muduo base库学习笔记 9——线程特定数据、线程本地当地类封装

线程特定数据

了解线程特定数据⭐

在单线程程序中,经常要用到“全局变量”以实现多个函数间共享数据。在多线程环境下,由于数据空间是共享的,全局变量也是所有线程所共有的。
但有时应用程序设计中有必要提供线程私有的全局变量,即仅在某个线程中有效,但却可以跨多个函数访问
POSIX线程库通过维护一定的数据结构来解决这个问题,这个数据成为Thread-specific Data或TSD,线程特定数据也称为线程本地存储TLS(Thread-local storage)

线程特定的数据结构:
muduo base库学习笔记 9——线程特定数据、线程本地当地类封装_第1张图片
一旦一个线程创建了一个pkey,那么其他线程也都有这样一个pkey,我们可以为特定的线程指定特定的数据(用pthread_key_t *key类型及其四个相关函数),这些数据就是线程所私有的, 这些私有的数据是堆上的数据, 要delete删除

对于POD类型的线程本地存储,可以用_thread关键字;对于非POD类型的线程本地存储,可以用TSD来解决

线程特定数据的用法⭐⭐

第一步:创建一个类型为pthread_key_t类型的变量
第二步:调用pthread_key_create()来创建该变量。该函数有两个参数,第一个参数就是上面的pthread_key_t变量,第二个参数是一个清理函数,用来在线程释放该线程存储时被调用。该函数指针可以设成NULL,这样系统将调用默认的清理函数

当线程中需要存储特殊值的时候,可以调用pthread_setspecific(),该函数有两个参数,第一个参数依旧是前面声明的pthread_key_t变量,第二个参数为void*变量,这样就可以存储任何类型的值

如果需要取出所存储的值,调用pthread_getspecific(),该函数的参数分别为pthread_key_t类型变量,返回void*类型的值

函数原型如下:

#include
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));//在创建中就已经把销毁线程的函数绑好了
int pthread_key_delete(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void* value);
void* pthread_getspecific(pthread_key_t key);

muduo base库学习笔记 9——线程特定数据、线程本地当地类封装_第2张图片
value()就是通过pthread_getspecific()来获取特定数据,看看:

// 返回实际数据
// 先判定指针是否为空,为空就创建该数据并设定,不为空则直接返回该数据
T& value()
{
    T* perThreadValue = static_cast<T*>(pthread_getspecific(pkey_)); //T类型
    if (!perThreadValue) {
      T* newObj = new T();
      pthread_setspecific(pkey_, newObj);
      perThreadValue = newObj;
    }
    return *perThreadValue;
}

销毁线程函数:

// pthread_key_create函数中设置的清理函数,用来销毁实际数据
static void destructor(void *x)
{
    T* obj = static_cast<T*>(x);
    typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];  // 检测是否是完全类型
    delete obj;//用delete
}

线程本地当地类封装

ThreadLocalSingleton封装
muduo base库学习笔记 9——线程特定数据、线程本地当地类封装_第3张图片instance返回单例对象
嵌套了一个Delete类,而这个Delete类又是借助于线程特定数据实现的

看muduo中的代码:

两个数据成员:
muduo base库学习笔记 9——线程特定数据、线程本地当地类封装_第4张图片
t_value_类型是T*, 加上了一个__thread关键字,表示这个指针每一个线程都有一份, deleter_用来销毁指针所指向的对象

其中单例对象的创建:
muduo base库学习笔记 9——线程特定数据、线程本地当地类封装_第5张图片
不需要用线程安全的方式去创建,因为每个线程都有t_value_指针,只需要按照普通方式实现, 如果指针为空就创建对象

同样在destructor中也用了typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];的断定,如果是不完全类型的话, 在编译器就会报错
muduo base库学习笔记 9——线程特定数据、线程本地当地类封装_第6张图片

你可能感兴趣的:(muduo源码,muduo,base,库)