1. 程式人生 > >從零開始構建一個Reactor模式的網路庫(二)執行緒類Thread

從零開始構建一個Reactor模式的網路庫(二)執行緒類Thread

執行緒類Thread是對POSIX執行緒的封裝類,因為要構建的是一個Linux環境下的多執行緒網路庫,對執行緒的封裝是很必要的。

首先是CurrentThread名稱空間,主要是獲取以及快取執行緒id:

 1 #ifndef CURRENTTHREAD_H
 2 #define CURRENTTHREAD_H
 3 #include <unistd.h>
 4 #include <sys/syscall.h>
 5 
 6 namespace CurrentThread
 7 {
 8     extern __thread int t_cachedTid;
 9
inline void cacheTid() 10 { 11 t_cachedTid=static_cast<int>(::syscall(SYS_gettid)); 12 } 13 inline int tid() 14 { 15 if(t_cachedTid==0) 16 cacheTid(); 17 return t_cachedTid; 18 } 19 } 20 21 #endif // CURRENTTHREAD_H

這裡要注意一個問題,就是執行緒id的獲取

執行緒id的獲取可以通過幾種方式,最方便的是syscall(),是一個glibc庫函式而不是一個系統呼叫,此時返回的是核心中的執行緒id。

因為Linux的執行緒實現中,執行緒事實上也是一個程序,因此返回的tid事實上就是pid,pid_t在Linux中一般實現為int。

另外,POSIX執行緒庫提供了函式pthread_self(),但是該函式返回的是程序中的執行緒id,型別為pthread_t,一般是unsigned long型別,並不是核心中的實際id,在除錯和排查錯誤時並不方便。

 1 #ifndef THREAD_H
 2 #define THREAD_H
 3 #include <pthread.h>
 4
#include <memory> 5 #include <functional> 6 #include "Types.h" 7 #include <atomic> 8 #include "Mutex.h" 9 10 namespace mini 11 { 12 class Thread 13 { 14 public: 15 typedef std::function<void()> ThreadFunc; 16 explicit Thread(const ThreadFunc& func,const string& ThreadName=string()); 17 ~Thread(); 18 19 int join(); 20 void start(); 21 pid_t tid() const { return *tid_; } 22 bool started() const { return started_; } 23 const string& name() const {return name_;} 24 private: 25 26 void setDefaultName(); 27 28 bool started_; //if the thread started 29 bool joined_; //if joined settled 30 pthread_t pthreadId_; //thread id in the process 31 std::shared_ptr<pid_t> tid_; //shared_ptr to the tid 32 string name_; //name of the thread 33 ThreadFunc func_; //function for the thread 34 static std::atomic<int> numsCreated_; //record nums of created threads 35 }; 36 37 } 38 39 #endif // THREAD_H

Thread.h標頭檔案中定義了Thread類,成員包括啟動狀態、tid和pthreadid、實際執行的函式以及名字等。

 1 #include "CurrentThread.h"
 2 #include "Thread.h"
 3 #include <stdio.h>
 4 #include <unistd.h>
 5 #include <sys/syscall.h>
 6 #include <sys/types.h>
 7 
 8 namespace CurrentThread
 9 {
10 __thread int t_cachedTid=0;
11 /*
12 bool isMainThread()
13 {
14     return ::getpid()==tid();
15 }
16 */
17 }
18 namespace mini
19 {
20 struct ThreadData
21 {
22     typedef mini::Thread::ThreadFunc ThreadFunc;
23     ThreadFunc func_;
24     mini::string name_;
25     std::weak_ptr<pid_t> wkTid_;
26     ThreadData(const ThreadFunc& func,const string& name,const std::shared_ptr<pid_t>& tid)
27         :func_(func),name_(name),wkTid_(tid)
28     {}
29     void runInThread()
30     {
31         pid_t tid=CurrentThread::tid();
32         std::shared_ptr<pid_t> ptid=wkTid_.lock();
33         if(ptid)
34         {
35             *ptid=tid;
36             ptid.reset();
37         }
38         func_();
39     }
40 
41 };
42 std::atomic<int> Thread::numsCreated_(0);
43 
44 void Thread::setDefaultName()
45 {
46     int num=numsCreated_++;
47     if(name_.empty())
48     {
49         char buf[32];
50         snprintf(buf,sizeof buf,"Thread%d", num);
51         name_=buf;
52     }
53 }
54 
55 void* startThread(void* obj)
56 {
57     ThreadData* data=static_cast<ThreadData*>(obj);
58     data->runInThread();
59     delete data;
60     return NULL;
61 }
62 
63 Thread::Thread(const ThreadFunc &func, const string &ThreadName)
64     :started_(false),
65       joined_(false),
66       pthreadId_(0),
67       tid_(new pid_t(0)),
68       func_(func),
69       name_(ThreadName)
70 {
71     setDefaultName();
72 }
73 
74 void Thread::start()
75 {
76     started_=true;
77     ThreadData* data=new ThreadData(func_,name_,tid_);
78     if(pthread_create(&pthreadId_,NULL,&startThread,data));
79     {
80         started_=false;
81         //delete data;
82         //LOG_SYSFATAL<<"FAILED in pthread_create";
83     }
84 }
85 
86 int Thread::join()
87 {
88     joined_=true;
89     return pthread_join(pthreadId_,NULL);
90 }
91 
92 Thread::~Thread()
93 {
94     if(started_&&!joined_)
95         pthread_detach(pthreadId_);
96 }
97 }

由於向pthread_create中傳遞要執行的執行緒函式以及引數比較複雜,定義了一個內部類ThreadData。

ThreadData中有一個weak_ptr<pid_t>,當執行緒實際被建立並開始執行時,建立一個臨時的shared_ptr,確保Thread以及ThreadData被正確建立。

事實上,Thread類物件建立時,執行緒並沒有實際開始執行,直到呼叫start()才開始執行。

執行執行緒可以呼叫join()來等待Thread執行緒的結束。預設情況下,執行緒資源會保留直到呼叫pthread_join()。

解構函式簡單地呼叫pthread_detach()來設定執行緒分離,從而線上程函式執行結束後直接退出,執行緒資源也會線上程終止時立即被回收