- 與muduo線程類封裝有關的源文件:
Thread.cc Thread.h CurrentThread.h - muduo線程類封裝實現方式:
基於對象的編程(利用boost::function/boost::bind實現) - 簡化版的線程類封裝可參考:
http://blog.csdn.net/jacktangj/article/details/76166554 - muduo線程類整體結構:
這裏簡化了成員函數以及全局函數
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);
}
};
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,結構體等),但用戶定義的帶有構造函數和虛函數的類則不是。