muduo庫源碼分析(4):線程類

  • 與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,結構體等),但用戶定義的帶有構造函數和虛函數的類則不是。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章