muduo库源码分析(4):线程类

来源:互联网 发布:云计算前景分析 编辑:程序博客网 时间:2024/06/05 07:20
  • 与muduo线程类封装有关的源文件:
    Thread.cc Thread.h CurrentThread.h
  • muduo线程类封装实现方式:
    基于对象的编程(利用boost::function/boost::bind实现)
  • 简化版的线程类封装可参考:
    http://blog.csdn.net/jacktangj/article/details/76166554
  • muduo线程类整体结构:

muduo线程类整体结构:
这里简化了成员函数以及全局函数
Thread类:线程类
CurrentThread命名空间:声明每个线程的私有数据
ThreadNameInitializer 类:用于初始化主线程的线程特有数据
ThreadData结构体:通过回调函数传递给子线程的数据

简单分析Thread类的运行过程。

  1. detail命名空间有全局变量init,会首先调用ThreadNameInitializer 类构造函数。以及包含静态成员numCreate_(原子类Automic)的初始化
    ThreadNameInitializer 类结构
class ThreadNameInitializer{ public:  ThreadNameInitializer()  {    muduo::CurrentThread::t_threadName = "main";    CurrentThread::tid();    pthread_atfork(NULL, NULL, &afterFork);  }};1.__thread int t_cachedTid;//线程实际ID的缓存,减少多次调用syscall(SYS_gettid)获取线程实际ID  __thread char t_tidString[32];//线程tid的字符串形式  __thread int t_tidStringLength;//线程tid的字符串形式的长度  __thread const char* t_threadName;// 线程的名字  __thread修饰的变量为每个线程的私有数据,不共享  只能修饰POD类型数据(后面注意2),非POD数据可用线程的特定数据实现2. inline int tid(){    if (__builtin_expect(t_cachedTid == 0, 0))    {      cacheTid();    }    return t_cachedTid;}__builtin_expect:gcc的编译优化语句,用于提前加载if的语句还是else语句void CurrentThread::cacheTid(){  if (t_cachedTid == 0)  {    t_cachedTid = detail::gettid();    t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid);  }}pid_t gettid(){  return static_cast<pid_t>(::syscall(SYS_gettid));}syscall(SYS_gettid)//获取线程的实际ID(后面注意1)3.pthread_atfork(prepare,parent,child)在fork之前执行prepare函数,fork后主进程执行parent,子进程执行child注意:多线程程序最好不要去fork,很容易造成死锁

2.构造Thread类的构造函数(Thread t(threadFunc);)

Thread::Thread(const ThreadFunc& func, const string& n)  : started_(false),//标记线程是否启动    joined_(false),// 标记线程是否连接,即pthread_join    pthreadId_(0),// 线程ID    tid_(new pid_t(0)),// 线程实际ID    func_(func),// 回调函数    name_(n)// 线程名{  setDefaultName();}void Thread::setDefaultName(){// 静态成员变量用于线程计数:原子性操作+1  int num = numCreated_.incrementAndGet();  if (name_.empty())  {    char buf[32];    snprintf(buf, sizeof buf, "Thread%d", num);    name_ = buf;  }}

3.执行(t.start();t.join();)

void Thread::start(){  assert(!started_);  started_ = true;  detail::ThreadData* data = new detail::ThreadData(func_, name_, tid_);  // 创建线程  if (pthread_create(&pthreadId_, NULL, &detail::startThread, data))  {    started_ = false;    delete data; // or no delete?    LOG_SYSFATAL << "Failed in pthread_create";//日志文件输出(后续)  }}void* startThread(void* obj){  ThreadData* data = static_cast<ThreadData*>(obj);  data->runInThread();  delete data;  return NULL;}

注意:
1.线程标识符:
进程———-线程
pid_t———-pthread_t
getpid()———-pthread_self()
标识符唯一———-不同进程拥有相同线程ID
linux中posix线程实现也是一个轻量级进程,只是该进程与主进程共享一些资源,有时需要实际的线程ID,例如p1->p2某个线程时,既不能用p2的pid也不能用改线程的pthread_self(),只能用线程的实际ID,获取方式调用:syscall(SYS_gettid)
2.POD类型:与C兼容的数据类型(int,double,结构体等),但用户定义的带有构造函数和虚函数的类则不是。

原创粉丝点击