muduo网络库源码学习————线程特定数据

muduo库线程特定数据源码文件为ThreadLocal.h

//线程本地存储
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)

#ifndef MUDUO_BASE_THREADLOCAL_H
#define MUDUO_BASE_THREADLOCAL_H

#include <boost/noncopyable.hpp>
#include <pthread.h>

namespace muduo
{

template<typename T>
class ThreadLocal : boost::noncopyable//不可拷贝
{
 public:
  ThreadLocal()
  {//构造函数创建key,ThreadLocal::destructor为销毁的回调函数
    pthread_key_create(&pkey_, &ThreadLocal::destructor);
  }

  ~ThreadLocal()
  {//析构函数销毁key,但并不是销毁实际的数据
    pthread_key_delete(pkey_);
  }

  T& value()
  {//获取线程特定数据
    T* perThreadValue = static_cast<T*>(pthread_getspecific(pkey_));
    if (!perThreadValue) //返回指针如果是空,说明特定数据还没有创建
    {
      T* newObj = new T();//创建数据
      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];//完全类型
    delete obj;//调用delete销毁数据
  }

 private:
  pthread_key_t pkey_;
};

}
#endif

有两个测试程序
ThreadLocal_test.cc

//线程本地存储测试程序
#include <muduo/base/ThreadLocal.h>
#include <muduo/base/CurrentThread.h>
#include <muduo/base/Thread.h>

#include <boost/noncopyable.hpp>
#include <stdio.h>

class Test : boost::noncopyable
{
 public:
  Test()
  {
    printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this);
  }

  ~Test()
  {
    printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str());
  }

  const std::string& name() const { return name_; }
  void setName(const std::string& n) { name_ = n; }

 private:
  std::string name_;
};
//定义两个线程特定数据对象,每个线程都有这样的对象
muduo::ThreadLocal<Test> testObj1;
muduo::ThreadLocal<Test> testObj2;

void print()//打印函数
{
  printf("tid=%d, obj1 %p name=%s\n",muduo::CurrentThread::tid(),&testObj1.value(),testObj1.value().name().c_str());
  printf("tid=%d, obj2 %p name=%s\n",muduo::CurrentThread::tid(),&testObj2.value(),testObj2.value().name().c_str());
}

void threadFunc()
{
  print();
  //testObj1.value()返回的是Test类型的引用
  testObj1.value().setName("changed 1");
  testObj2.value().setName("changed 42");
  print();
}

int main()
{
  testObj1.value().setName("main one");
  print();
  //创建线程,每个线程都有自己的testObj1,testObj2
  muduo::Thread t1(threadFunc);
  t1.start();//启动线程
  t1.join();
  testObj2.value().setName("main two");
  print();

  pthread_exit(0);//退出主线程
}

执行结果如下:
这里写图片描述

SingletonThreadLocal_test.cc

#include <muduo/base/Singleton.h>
#include <muduo/base/CurrentThread.h>
#include <muduo/base/ThreadLocal.h>
#include <muduo/base/Thread.h>

#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>
#include <stdio.h>

class Test : boost::noncopyable
{
 public:
  Test()
  {
    printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this);
  }

  ~Test()
  {
    printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str());
  }

  const std::string& name() const { return name_; }
  void setName(const std::string& n) { name_ = n; }

 private:
  std::string name_;
};
//单例对象:muduo::Singleton<muduo::ThreadLocal<Test> >::instance(),value是线程特定数据,每个线程都有的
#define STL muduo::Singleton<muduo::ThreadLocal<Test> >::instance().value()

void print()
{//打印函数
  printf("tid=%d, %p name=%s\n",muduo::CurrentThread::tid(),&STL,STL.name().c_str());
}

void threadFunc(const char* changeTo)
{
  print();
  STL.setName(changeTo);//设置线程特定数据的名称
  sleep(1);//睡眠
  print();
}

int main()
{
  STL.setName("main one");//设置线程特定数据的名称
  //创建两个线程,threadFunc带参数
  muduo::Thread t1(boost::bind(threadFunc, "thread1"));
  muduo::Thread t2(boost::bind(threadFunc, "thread2"));
  //启动两个线程
  t1.start();
  t2.start();
  t1.join();
  print();
  t2.join();
  pthread_exit(0);
}

执行结果如下:
这里写图片描述

posted @ 2015-08-29 21:34  sigma0  阅读(147)  评论(0编辑  收藏  举报