【Muduo源码剖析笔记】 基础组件之线程库

【Muduo源码剖析笔记】 基础组件之线程库

CurrentThread

  • __builtin_expect:作用是允许程序员将最有可能执行的分支告诉编译器。这个指令的写法为:__builtin_expect(EXP, N)。目的是将“分支转移”的信息提供给编译器,这样编译器可以对代码进行优化,以减少指令跳转带来的性能下降。

  • C++11中引入了static_assert这个关键字,用来做编译期间的断言,因此叫作静态断言。

static_assert(常量表达式,"提示字符串")
  • backtrace
#include <execinfo.h>
int backtrace(void **buffer, int size);

该函数获取当前线程的调用堆栈,获取的信息将会被存放在buffer中,它是一个指针数组,参数size用来指定buffer中可以保存多少个void元素。函数的返回值是实际返回的void元素个数。buffer中的void*元素实际是从堆栈中获取的返回地址。

char **backtrace_symbols(void *const *buffer, int size);

该函数将backtrace函数获取的信息转化为一个字符串数组,参数buffer是backtrace获取的堆栈指针,size是backtrace返回值。函数返回值是一个指向字符串数组的指针,它包含char*元素个数为size。每个字符串包含了一个相对于buffer中对应元素的可打印信息,包括函数名、函数偏移地址和实际返回地址。

CurrentThread命名空间仅仅声明了几个__thread关键字管理的 线程相关数据和相关函数。

Thread

bool started_;

bool joined_;

pthread_t pthreadId_;

pid_t tid_;

ThreadFunc func_;

string name_;

CountDownLatch latch_;

static AtomicInt32 numCreated_; 一个静态的,意义是表示创建了多少个线程。

初始化函数:started和joied都默认false,pthreadID是0,tid也是0,会有一个func初始化ThreadFun func。latch_初始值为1。

cacheTid():如果t_cachedTid为0(也就是这个线程的缓存ID还标志着主线程,就会更新缓存数据。)。然后调用gettid(),会调用系统调用::syscall(SYS_gettid)获得当前线程id,并且给t_cachedTid。

start()函数:会用func_、name_、&tid_和&latch_,初始化一个ThreadData* data。这份数据保存在主线程中,然后调用pthread_create创建线程,并且调用startThread函数,传入一份data作为参数。

startThread(void* obj):会传入一个ThreadData* data参数,然后再线程本地栈创建一个局部变量指针指向这部分数据,并且运行data里面的runInThread()函数。

runInThread():首先会调用CurrentThread命名空间中的tid()函数,tid函数会调用cacheTid(),获取当前线程ID保存在t_cachedTid中,然后tid()返回t_cachedTid给data的tid_。所以每个线程会有一个指向data数据格式的指针,主线程也拥有这个data,保存和这个线程相关的信息。同时也有几个由__thread关键字描述的数据变量。

ThreadLocal

主线程创建ThreadLocal类的实例,调用默认初始化函数,其中调用pthread_key_create创建键值。可以理解为一个键值就对应一份线程特有数据。每个T类型的ThreadLocal实例都可以有一份自己的键值,也就是对应线程特有数据。子线程通过防卫value函数来获取自己的那一份。

子线程都可以通过访问这个键值来获取T类型的变量。

调用T& value()函数,通过pKey_这个键值获取线程特有的数据。

ThreadLocalSingleton

主线程创建ThreadLocalSingleton实例,该类的作用域内包含static __thread T* t_value_的线程特有数据指针,当调用instance()的时候,判断每个线程持有的指针是否为0,如果为0的话,就是还没有为该线程分配对象。因此就会使用Deleter来为t_value分配数据。

Deleter是static的,全局变量对于一类只有一份,自己内部有一个键值,只有这个键值来进行数据分配。

ThreadPool

ThreadPool类包含了一个锁成员,两个条件变量。包含一个string类型的name_变量,一个Task类型的threadInitCallback_变量。Task是一个函数对象类,返回值为void,无参数。

有一个vector,装有指向Thread类对象的线程指针,threads_。一个deque<Task>类型的queue。

start(int numThreads):根据numThreads的数量,依次使用runInTread函数初始化muduo::Thread,然后把Thread塞入threads中。也就是threads_里面的线程会默认使用ThreadPool::runInThread函数。然后调用Thread_对象的start(),start函数就会创建线程,然后运行runInthread。

RunInThread():如果有线程初始化函数,调用线程初始化函数,然后从take(),取得任务,然后运行该任务

take():如果任务队列是空的,就会等待。队列如果有任务进去,就会发起非空的通知,这个时候就可以拿任务。如果队列有位置了,也会发起还没满的通知,让队列可以加入新的任务。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值