ThreadLocal

template<typename T>
class ThreadLocal : noncopyable
{
 public:
  ThreadLocal()
  {
    MCHECK(pthread_key_create(&pkey_, &ThreadLocal::destructor));
  }

  ~ThreadLocal()
  {
    MCHECK(pthread_key_delete(pkey_));
  }

  T& value()
  {
    T* perThreadValue = static_cast<T*>(pthread_getspecific(pkey_));
    if (!perThreadValue)
    {
      T* newObj = new T();
      MCHECK(pthread_setspecific(pkey_, newObj));
      perThreadValue = newObj;
    }
    return *perThreadValue;
  }

 private:

  static void destructor(void *x)
  {
    T* obj = static_cast<T*>(x);
    typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
    T_must_be_complete_type dummy; (void) dummy;
    delete obj;
  }

 private:
  pthread_key_t pkey_;
};

类ThreadLocal实际上就是封装了线程特有数据,所以主要介绍下线程特有数据,了解了线程特有数据,该类就很简单了。简单起见,直接摘抄《Linux/UNIX系统编程手册》了,哈哈。。。

要使用线程特有数据,库函数执行的一般步骤如下:

  1. 函数创建一个键(key),用以将不同函数使用的线程特有数据项区分开来。调用函数pthread_key_create()可创建此“键”,且只需在首个调用该函数的线程中创建一次。键在创建时并未分配任何线程特有数据块。
  2. 调用pthread_key_create()还有另一个目的,即允许调用者指定一个自定义解构函数,用于释放为该键所分配的各个存储块。当使用线程特有数据的线程终止时,Pthreads API会自动调用此解构函数,同时将该线程的数据块指针作为参数传入。
  3. 函数会为每个调用者线程创建线程特有数据块。这一分配通过调用malloc()(或类似函数)完成,每个线程只分配一次,且只会在线程初次调用此函数时分配。
  4. 为了保存上一步所分配存储块的地址,会使用两个Pthreads函数:pthread_setspecific()和pthread_getspecific()。调用函数pthread_setspecific()实际上是对Pthreads实现发起这样的请求:保存该指针,并记录其与特定键(该函数的键)以及特定线程(调用者线程)的关联性。调用pthread_getspecific()所执行的是互补操作:返回之前所保存的、与给定键以及调用线程相关联的指针。如果还没有指针与特定的键及线程相关联,那么pthread_getspecific()返回NULL。函数可以利用这一点来判断自身是否是初次为某个线程所调用,若为初次,则必须为该线程分配空间。

在ThreadLocal类中,构造函数执行了上面的第1步和第2步,即创建key,并定义解构函数。在析构函数中删除键,在上面的4步中并没有提到。在成员函数value中,使用pthread_getspecific获取线程特有数据块,如果为NULL,为该线程分配空间。即上面的第3步。并使用pthread_setspecific保存该指针,之后再调用pthread_getspecific就可以直接获取该指针。即为上面的第4步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值