-
與muduo線程類封裝有關的源檔案:
Thread.cc Thread.h CurrentThread.h
-
muduo線程類封裝實作方式:
基于對象的程式設計(利用boost::function/boost::bind實作)
-
簡化版的線程類封裝可參考:
http://blog.csdn.net/jacktangj/article/details/76166554
- muduo線程類整體結構:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0NXYFhGd192UvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcFHZtJGaSNTYqZUbhZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jNyMjNyEDNxIzNycDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
這裡簡化了成員函數以及全局函數
Thread類:線程類
CurrentThread命名空間:聲明每個線程的私有資料
ThreadNameInitializer 類:用于初始化主線程的線程特有資料
ThreadData結構體:通過回調函數傳遞給子線程的資料
簡單分析Thread類的運作過程。
-
detail命名空間有全局變量init,會首先調用ThreadNameInitializer 類構造函數。以及包含靜态成員numCreate_(原子類Automic)的初始化
ThreadNameInitializer 類結構
class ThreadNameInitializer
{
public:
ThreadNameInitializer()
{
muduo::CurrentThread::t_threadName = "main";
CurrentThread::tid();
pthread_atfork(NULL, NULL, &afterFork);
}
};
__thread int t_cachedTid;//線程實際ID的緩存,減少多次調用syscall(SYS_gettid)擷取線程實際ID
__thread char t_tidString[];//線程tid的字元串形式
__thread int t_tidStringLength;//線程tid的字元串形式的長度
__thread const char* t_threadName;// 線程的名字
__thread修飾的變量為每個線程的私有資料,不共享
隻能修飾POD類型資料(後面注意),非POD資料可用線程的特定資料實作
inline int tid()
{
if (__builtin_expect(t_cachedTid == , ))
{
cacheTid();
}
return t_cachedTid;
}
__builtin_expect:gcc的編譯優化語句,用于提前加載if的語句還是else語句
void CurrentThread::cacheTid()
{
if (t_cachedTid == )
{
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)
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_(),// 線程ID
tid_(new pid_t()),// 線程實際ID
func_(func),// 回調函數
name_(n)// 線程名
{
setDefaultName();
}
void Thread::setDefaultName()
{
// 靜态成員變量用于線程計數:原子性操作+1
int num = numCreated_.incrementAndGet();
if (name_.empty())
{
char buf[];
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,結構體等),但使用者定義的帶有構造函數和虛函數的類則不是。