muduo源码解析15-thread类
thread类:
//namespace mymuduo class thread { }; //namespace mymuduo::detail struct ThreadData { };
作用:
两个重要的类mymuduo::thread和mymuduo::detail::ThreadData
thread类实现了对于线程的封装,内部提供了start(),join(),和一些返回线程状态信息的方法
ThreadData类封装了线程数据信息,包括线程名字,ID,线程函数,倒计时计数信息.这个类主要用于
pthread_create()函数中作为线程传参而使用的.
下面说一下创建线程并且执行的完成的步骤:
thread类在构造函数中完成线程信息的初始化,即初始化类内部成员变量
调用start()启动线程,实际上用pthread_create()启动线程,传入ThreadData对象指针作为线程
传参,注意该处pthread_create()并不是直接调用m_func线程函数,而是间接调用detail::startThread
函数,之后在startThread函数中获取ThreadData信息,并执行ThreadData::runInThread函数完成
具体的线程函数m_func的调用
简略步骤:
thread::thread() //设置线程信息成员变量
thread::start() //pthread_create,调用detail::startThread(),传参ThreadData
detail::startThread() //内部调用ThreadData::runInThread(),完成m_func线程函数调用
还需要注意之前的currentthread名字空间中有的函数仅是声明而未实现,例如currentthread::cacheTid()
在这里进行了实现,并且对currentthread中的四个全局变量(线程ID,名字等)提供了相应的设置函数.
ThreadData成员变量:
public: typedef thread::ThreadFunc ThreadFunc; ThreadFunc m_func; //线程函数 string m_name; //线程名字 pid_t* m_tid; //线程ID countdownlatch* m_latch; //倒计时计数
用于保存基本线程信息
ThreadData成员函数:
//构造函数初始化 ThreadData(ThreadFunc func,const string& name,pid_t* tid,countdownlatch* latch) :m_func(std::move(func)),m_name(name),m_tid(tid),m_latch(latch) { } //运行线程 void runInThread() { //设置类成员变量 *m_tid=currentthread::tid(); m_tid=NULL; m_latch->countDown(); m_latch=NULL; //设置线程名字 currentthread::t_threadName=m_name.empty()?"muduoThread":m_name.data(); ::prctl(PR_SET_NAME,currentthread::t_threadName); try { m_func(); //具体的运行函数 currentthread::t_threadName="finished"; //执行结束 } catch (const mymuduo::exception& ex) { currentthread::t_threadName = "crashed"; fprintf(stderr, "exception caught in Thread %s\n", m_name.c_str()); fprintf(stderr, "reason: %s\n", ex.what()); fprintf(stderr, "stack trace: %s\n", ex.stackTree()); abort(); }catch(const std::exception& ex) { currentthread::t_threadName = "crashed"; fprintf(stderr, "exception caught in Thread %s\n", m_name.c_str()); fprintf(stderr, "reason: %s\n", ex.what()); abort(); }catch(...) { currentthread::t_threadName="crashed"; fprintf(stderr,"unknown exception caught in Thread %s\n", m_name.c_str()); throw; } }
thread成员变量:
private: bool m_started; //线程是否启动 bool m_joined; //是否被join回收 pthread_t m_pthreadId; //线程ID pid_t m_tid; //进程ID ThreadFunc m_func; //线程函数 string m_name; //线程名字 countdownlatch m_latch; //倒计时计数 static atomicInt32 m_numCreated; //本进程创建的线程数量
thread成员函数:
public: typedef std::function<void()> ThreadFunc; //构造函数,调用setDefaultName,用于各种成员传入参数 explicit thread(ThreadFunc,const string& name=string()); //析构函数负责把线程detach让其自己销毁 ~thread(); void start(); int join(); //返回内部成员线程是否启动,线程ID,线程名字 bool started() const {return m_started;} pid_t tid() const {return m_tid;} const string& name() const {return m_name;} //返回本进程创建的线程数目 static int numCreated(){return m_numCreated.get();} private: //设置m_name void setDefaultName();
thread.h:
#ifndef THREAD_H #define THREAD_H #include"base/atomic.h" #include"base/countdownlatch.h" #include"base/types.h" #include<functional> #include<memory> #include<pthread.h> namespace mymuduo{ class thread { public: typedef std::function<void()> ThreadFunc; //构造函数,调用setDefaultName,用于各种成员传入参数 explicit thread(ThreadFunc,const string& name=string()); //析构函数负责把线程detach让其自己销毁 ~thread(); void start(); int join(); //返回内部成员线程是否启动,线程ID,线程名字 bool started() const {return m_started;} pid_t tid() const {return m_tid;} const string& name() const {return m_name;} //返回本进程创建的线程数目 static int numCreated(){return m_numCreated.get();} private: //设置m_name void setDefaultName(); bool m_started; //线程是否启动 bool m_joined; //是否被join回收 pthread_t m_pthreadId; //线程ID pid_t m_tid; //进程ID ThreadFunc m_func; //线程函数 string m_name; //线程名字 countdownlatch m_latch; //倒计时计数 static atomicInt32 m_numCreated; //本进程创建的线程数量 }; } #endif // THREAD_H
thread.cpp:
#include "thread.h" #include"base/currentthread.h" #include"base/exception.h" #include"base/exception.h" #include"base/logging.h" #include<type_traits> #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 mymuduo { namespace detail{ //得到唯一的线程ID pid_t gettid() { return static_cast<pid_t>(::syscall((SYS_gettid))); } //currentthread中以前定义了四个__thread变量,用来描述线程信息,在这里进行设置 void afterFork() { currentthread::t_cachedTid=0; currentthread::t_threadName="main"; currentthread::tid(); } //线程初始化函数,负责初始化线程信息 class ThreadNNameInitializer { public: ThreadNNameInitializer() { currentthread::t_threadName="main"; currentthread::tid(); pthread_atfork(NULL,NULL,&afterFork); } }; //全局线程初始化对象,完成currentthread中线程全局变量的设置 ThreadNNameInitializer init; //线程数据类, struct ThreadData { typedef thread::ThreadFunc ThreadFunc; ThreadFunc m_func; //线程函数 string m_name; //线程名字 pid_t* m_tid; //线程ID countdownlatch* m_latch; //倒计时计数 //构造函数初始化 ThreadData(ThreadFunc func,const string& name,pid_t* tid,countdownlatch* latch) :m_func(std::move(func)),m_name(name),m_tid(tid),m_latch(latch) { } //运行线程 void runInThread() { //设置类成员变量 *m_tid=currentthread::tid(); m_tid=NULL; m_latch->countDown(); m_latch=NULL; //设置线程名字 currentthread::t_threadName=m_name.empty()?"muduoThread":m_name.data(); ::prctl(PR_SET_NAME,currentthread::t_threadName); try { m_func(); //具体的运行函数 currentthread::t_threadName="finished"; //执行结束 } catch (const mymuduo::exception& ex) { currentthread::t_threadName = "crashed"; fprintf(stderr, "exception caught in Thread %s\n", m_name.c_str()); fprintf(stderr, "reason: %s\n", ex.what()); fprintf(stderr, "stack trace: %s\n", ex.stackTree()); abort(); }catch(const std::exception& ex) { currentthread::t_threadName = "crashed"; fprintf(stderr, "exception caught in Thread %s\n", m_name.c_str()); fprintf(stderr, "reason: %s\n", ex.what()); abort(); }catch(...) { currentthread::t_threadName="crashed"; fprintf(stderr,"unknown exception caught in Thread %s\n", m_name.c_str()); throw; } } }; //从属于detail命名空间,使用ThreadData类创建并且启动线程 void* startThread(void* obj) { ThreadData* data = static_cast<ThreadData*>(obj); data->runInThread(); delete data; return NULL; } }//namespace detail //之前currentthread中没有定义此方法,因此在这里进行定义 void currentthread::cacheTid() { //设置 __thread修饰的 currentthread::线程ID,线程名字长度 if (t_cachedTid == 0) { t_cachedTid = detail::gettid(); t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid); } } //判断是否是主线程,进程ID是否是线程ID 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::microSecInSec); ts.tv_nsec = static_cast<long>(usec % timestamp::microSecInSec * 1000); ::nanosleep(&ts, NULL); //挂起当前线程 } //thread类中的static 变量,表示当前进程创建的线程数目 atomicInt32 thread::m_numCreated; //构造函数,初始化线程信息,是否启动,回收,线程ID,进程ID,执行函数,线程名字,倒计时计数 thread::thread(ThreadFunc func, const string& n) : m_started(false), m_joined(false), m_pthreadId(0), m_tid(0), m_func(std::move(func)), m_name(n), m_latch(1) { setDefaultName(); //构造时确定名字 } //析构时把线程detach,不用父进程回收子线程 thread::~thread() { if (m_started && !m_joined) { pthread_detach(m_pthreadId); } } //设置线程名字,格式为 "Thread%d" void thread::setDefaultName() { //当前进程的线程数目++ int num = m_numCreated.incrementAndGet(); if (m_name.empty()) { char buf[32]; snprintf(buf, sizeof buf, "Thread%d", num); m_name = buf; } } //启动,利用pthread_create()创建一个线程去执行detail::startThread函数 //把ThreadData指针作为参数传入,在startThread函数中执行ThreadData::runInThread //完成具体的线程函数调用 void thread::start() { assert(!m_started); m_started = true; // FIXME: move(func_) detail::ThreadData* data = new detail::ThreadData(m_func, m_name, &m_tid, &m_latch); if (pthread_create(&m_pthreadId, NULL, &detail::startThread, data)) { //线程创建失败 m_started = false; delete data; // or no delete? LOG_SYSFATAL << "Failed in pthread_create"; } else { //线程创建成功 m_latch.wait(); assert(m_tid > 0); } } //回收子线程 int thread::join() { assert(m_started); assert(!m_joined); m_joined = true; return pthread_join(m_pthreadId, NULL); } }
测试:
#include"base/thread.h" #include<iostream> #define __STDC_FORMAT_MACROS #include <inttypes.h> using namespace std; void workerthread1() { //线程函数内部调用currentthread提供的全局变量/函数来获取线程信息 mymuduo::currentthread::sleepUsec(1000000); std::cout<<mymuduo::currentthread::name()<<" "; std::cout<<mymuduo::currentthread::tid()<<std::endl; } void workerthread2() { mymuduo::currentthread::sleepUsec(1000000); std::cout<<mymuduo::currentthread::name()<<" "; std::cout<<mymuduo::currentthread::tid()<<std::endl; } mymuduo::thread::ThreadFunc tfunc; int main() { tfunc=workerthread1; mymuduo::thread t1(tfunc,"I'm thread1"); t1.start(); //通过thread提供的方法来获取线程信息 std::cout<<t1.name()<<" "<<t1.tid()<<std::endl; tfunc=workerthread2; mymuduo::thread t2(tfunc,"I'm thread2"); t2.start(); //通过thread提供的方法来获取线程信息 std::cout<<t2.name()<<" "<<t2.tid()<<std::endl; std::cout<<"当前创建的线程数目: "<<mymuduo::thread::numCreated()<<std::endl; t1.join();t2.join(); std::cout<<"over...\n"; }
打印结果:
I'm thread1 91612
I'm thread2 91613
当前创建的线程数目: 2
I'm thread1 91612
I'm thread2 91613
over...