- 与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,结构体等),但用户定义的带有构造函数和虚函数的类则不是。