[Muduo网络库源码分析] (9) base/Thread.cc_h_CurrentThread_h线程对象

线程对象

实现:实现Thread类、ThreadData结构体 、CurrentThread命名空间


功能:实现线程对象并实现当前线程信息存储


知识点:

  • __thread
    __thread是GCC内置的线程局部存储设施,存取效率可以和全局变量相比。__thread变量每一个线程有一份独立实体,各个线程的值互不干扰。可以用来修饰那些带有全局性且值可能变,但是又不值得用全局变量保护的变量。
    __thread使用规则:只能修饰POD类型(类似整型指针的标量,不带自定义的构造、拷贝、赋值、析构的类型,二进制内容可以任意复制memset,memcpy,且内容可以复原),不能修饰class类型,因为无法自动调用构造函数和析构函数,可以用于修饰全局变量,函数内的静态变量,不能修饰函数的局部变量或者class的普通成员变量,且__thread变量值只能初始化为编译器常量(值在编译器就可以确定const int i=5,运行期常量是运行初始化后不再改变const int i=rand()).

  • Pthread_atfork()函数

  • boost::weak_pt弱指针

  • prctl函数


用途:

可用于创建线程,创建多线程程序,可用于创建线程池。

模块拆分与封装:

已把其线程对象模块单独分离出来,并利用Makefile统一编译,模块代码地址如下:https://github.com/chudongfang/Learn_From_Muduo/tree/master/Thread

代码及分析:

Thread.cc
// 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)

#include <muduo/base/Thread.h>
#include <muduo/base/CurrentThread.h>
#include <muduo/base/Exception.h>
#include <muduo/base/Logging.h>

#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/weak_ptr.hpp>

#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <linux/unistd.h>

namespace muduo
{
namespace CurrentThread
{
  //线程id
  __thread int t_cachedTid = 0;


  //线程名
  __thread char t_tidString[32];
  __thread int t_tidStringLength = 6;

  __thread const char* t_threadName = "unknown";

  //判断int和pid_t类型是否相同
  const bool sameType = boost::is_same<int, pid_t>::value;
  //如果类型不相同则断言false,编译出错  ??
  BOOST_STATIC_ASSERT(sameType);
}

namespace detail
{
//通过系统调用syscall获取当前线程
pid_t gettid()
{
  return static_cast<pid_t>(::syscall(SYS_gettid));
}
//更新当前线程信息
void afterFork()
{
  muduo::CurrentThread::t_cachedTid = 0;
  muduo::CurrentThread::t_threadName = "main";
  CurrentThread::tid();
  // no need to call pthread_atfork(NULL, NULL, &afterFork);
}

// 该类用于初始化CurrentThread信息为当先主线程信息,并且在创建子线程时更新CurrentThread信息
class ThreadNameInitializer
{
 public:
  ThreadNameInitializer()
  {
    muduo::CurrentThread::t_threadName = "main";
    //获取当前ID信息
    CurrentThread::tid();
    //子进程执行afterfork
    //pthread_atfork(fork前函数,父进程执行的函数,子线程执行的函数)
    pthread_atfork(NULL, NULL, &afterFork);
  }
};

//初始CurrentThread信息
ThreadNameInitializer init;
//以ThreadData的数据形式向子线程传参
struct ThreadData
{
  typedef muduo::Thread::ThreadFunc ThreadFunc;
  ThreadFunc func_;
  string name_;
  //智能指针,弱引用,不对引用计数器加一
  //用来观察
  boost::weak_ptr<pid_t> wkTid_;

  ThreadData(const ThreadFunc& func,
             const string& name,
             const boost::shared_ptr<pid_t>& tid)
    : func_(func),
      name_(name),
      wkTid_(tid)
  { }

  void runInThread()
  {

    //得到当前线程ID
    pid_t tid = muduo::CurrentThread::tid();

    //获取所管理的对象的强引用指针。
    boost::shared_ptr<pid_t> ptid = wkTid_.lock();
    //修改主进程类中pid_为当前进程ID
    if (ptid)
    {
      *ptid = tid;
      ptid.reset();
    }

    muduo::CurrentThread::t_threadName = name_.empty() ? "muduoThread" : name_.c_str();
    //设置进程名
    ::prctl(PR_SET_NAME, muduo::CurrentThread::t_threadName);
    try
    {
      //运行函数
      func_();
      //运行完成修改CurrentThread中线程名
      muduo::CurrentThread::t_threadName = "finished";
    }
    catch (const Exception& ex)
    {
      //对于其抛出的异常类,显示erro
      muduo::CurrentThread::t_threadName = "crashed";
      fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
      fprintf(stderr, "reason: %s\n", ex.what());
      fprintf(stderr, "stack trace: %s\n", ex.stackTrace());
      abort();
    }
    catch (const std::exception& ex)
    {
      muduo::CurrentThread::t_threadName = "crashed";
      fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
      fprintf(stderr, "reason: %s\n", ex.what());
      abort();
    }
    catch (...)
    {
      muduo::CurrentThread::t_threadName = "crashed";
      fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str());
      throw; // rethrow
    }
  }
};
//子线程函数
//开始线程
void* startThread(void* obj)
{
  ThreadData* data = static_cast<ThreadData*>(obj);
  data->runInThread();
  delete data;
  return NULL;
}

}
}

using namespace muduo;
//获取当前线程ID,并赋值给变量
void CurrentThread::cacheTid()
{
  if (t_cachedTid == 0)
  {
    t_cachedTid = detail::gettid();
    t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid);
  }
}
//判断是否是主线程
bool CurrentThread::isMainThread()
{
  return tid() == ::getpid();
}


//调用系统调用实现延时
void CurrentThread::sleepUsec(int64_t usec)
{
  struct timespec ts = { 0, 0 };
  ts.tv_sec = static_cast<time_t>(usec / Timestamp::kMicroSecondsPerSecond);
  ts.tv_nsec = static_cast<long>(usec % Timestamp::kMicroSecondsPerSecond * 1000);
  ::nanosleep(&ts, NULL);
}




AtomicInt32 Thread::numCreated_;

//主线程函数
Thread::Thread(const ThreadFunc& func, const string& n)//构造函数,初始化线程
  : started_(false),
    joined_(false),
    pthreadId_(0),
    tid_(new pid_t(0)),
    func_(func),
    name_(n)
{
  setDefaultName();
}

#ifdef __GXX_EXPERIMENTAL_CXX0X__
Thread::Thread(ThreadFunc&& func, const string& n)
  : started_(false),
    joined_(false),
    pthreadId_(0),
    tid_(new pid_t(0)),
    func_(std::move(func)),
    name_(n)
{
  setDefaultName();
}

#endif

//主线程函数
Thread::~Thread()//如何子线程未完成,将其与父线程分离
{
  if (started_ && !joined_)
  {
    pthread_detach(pthreadId_);
  }
}


//主线程函数
//给线程对象命名
void Thread::setDefaultName()
{
  int num = numCreated_.incrementAndGet();//原子操作
  if (name_.empty())
  {
    char buf[32];
    snprintf(buf, sizeof buf, "Thread%d", num);
    name_ = buf;
  }
}

//主线程函数
void Thread::start()//开启线程
{
  assert(!started_);
  started_ = true;
  // FIXME: move(func_)
  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";
  }
}

//主线程函数
int Thread::join()//线程阻塞
{
  assert(started_); 
  //assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行
  assert(!joined_);
  joined_ = true;
  return pthread_join(pthreadId_, NULL);
}



Thread.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_THREAD_H
#define MUDUO_BASE_THREAD_H

#include <muduo/base/Atomic.h>
#include <muduo/base/Types.h>

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

namespace muduo
{

class Thread : boost::noncopyable
{
 public:
  typedef boost::function<void ()> ThreadFunc;

  explicit Thread(const ThreadFunc&, const string& name = string());
#ifdef __GXX_EXPERIMENTAL_CXX0X__
  explicit Thread(ThreadFunc&&, const string& name = string());
#endif
  ~Thread();

  void start();//开始
  int join(); // return pthread_join() 阻塞

  bool started() const { return started_; }//返回是否开始
  // pthread_t pthreadId() const { return pthreadId_; }
  pid_t tid() const { return *tid_; }//
  const string& name() const { return name_; }//返回线程名

  static int numCreated() { return numCreated_.get(); }//初始化numCreated

 private:
  void setDefaultName();//设置默认名

  bool       started_;//是否开始运行
  bool       joined_; //是否阻塞
  pthread_t  pthreadId_;//线程ID
  boost::shared_ptr<pid_t> tid_;//CurrentThread中的ID
  ThreadFunc func_;//线程函数
  string     name_;//线程名

  static AtomicInt32 numCreated_;//初始化32位原子整数
};

}
#endif

CurrentThread.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_CURRENTTHREAD_H
#define MUDUO_BASE_CURRENTTHREAD_H

#include <stdint.h>

namespace muduo
{
namespace CurrentThread
{
  // internal
  //记录当前线程信息
  extern __thread int t_cachedTid;
  extern __thread char t_tidString[32];
  extern __thread int t_tidStringLength;
  extern __thread const char* t_threadName;
  void cacheTid();

  //得到当前线程ID
  inline int tid()
  {
    //性能优化,t_cachedTid==0 的情况很少发生。
    if (__builtin_expect(t_cachedTid == 0, 0))
    {
      cacheTid();
    }
    return t_cachedTid;
  }

  inline const char* tidString() // for logging
  {
    return t_tidString;
  }

  inline int tidStringLength() // for logging
  {
    return t_tidStringLength;
  }
  //记录线程名字
  inline const char* name()
  {
    return t_threadName;
  }
  //判断是否是主线程
  bool isMainThread();

  void sleepUsec(int64_t usec);
}
}

#endif
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值