简介
在ceph中,很多任务都是用thread实现的,比如说adminsocket, log, timer等.可以说,thread是ceph中最基本的模块,因此我们的ceph源码分析从thread开始.本篇主要介绍三部分内容:
- thread
- mutex
- condition variable
thread
源码文件:
- src/common/thread.h
- src/common/thread.cc
class Thread
主要数据成员:
pthread_t thread_id: 线程id
pid_t pid: 线程pid,由linux的系统调用gettid()返回,其它系统无此系统调用,主要用于设置线程的调度优先级和cup亲和性
int ioprio_classs, ioprio_priority: 线程的调度优先级
int cupid: 线程的cpuid,即亲和性
const char *thread_name: 线程名称,长度必须小于16
主要成员函数:
create(): 相当于pthread_create,创建线程,并执行线程的启动函数
join(): 相当于pthread_join, 销毁线程
kill(): 相当于pthread_kill
重点是线程的创建:
create():
设置thread_name,并调用try_create()创建线程
try_create():
设置线程属性,主要是线程栈的大小stacksize.
设置线程的信号集屏蔽字.
调用pthread_create()创建线程.即:
pthread_create(&thread_id, thread_attr, _entry_func, (void *)this)
线程启动函数为_entry_func, 参数为this.
entry_func():
调用entry_wrapper()
即(Thread *)this->entry_wrapper(),
这里的this指针是当前对象的地址,
如果有类继承自Thread,
那么这里会发生多态绑定.
entry_wrapper()
设置线程的调度优先级
设置线程的cpu亲和性
调用entry()执行工作
entry()
线程类Thread是一个虚基类,entry是其唯一的纯虚函数,用于执行真正的工作.
每个继承Thread的类都必须重新定义自己的entry()函数.
mutex
源码文件
- src/common/mutex.h
- src/common/mutex.cc
class Mutex
主要数据成员:
string name: 互斥锁的名称
int id: 与锁的错误检查有关
bool recursive: // PTHREAD_MUTEX_RECURSIVE 互斥锁带递归属性
bool lockdep: // PTHREAD_MUTEX_ERRORCHECK 互斥锁带错误检查属性
bool backtrace:
pthread_mutex_t _m: 互斥锁
int nlock: 加锁次数,为0表示没有加锁,为正表示已经加锁
pthread_t locked_by: 加锁的线程
CephContext *cct;
PerfCounters *logger; 锁的统计计数
主要成员函数:
Mutex():
如果cct不为空,设置锁的性能统计值perfcount
如果recursive为真,设置锁的递归属性
如果lockdep为真,设置锁的错误检查属性
初始化互斥锁pthread_mutex_t _m
_post_lock():
执行加锁之后的一些工作
如果锁是普通锁,而不是递归锁,那么确保加锁之前nlock为0,即锁处于解锁状态,加锁之后nlock不为0,即nlock++.
并且设置locked_by为加锁线程的pid.
_pre_unlock():
执行解锁之前的一些工作
如果锁是普通锁,而不是递归锁,那么确保加锁之前nlock不为0,即锁处于加锁状态,解锁之后nlock为0,即nlock--,
解锁之前还必须检查locked_by和当前解锁线程的pid,确保同一个线程对锁进行加锁解锁工作.
TryLock():
pthread_mutex_trylock()尝试加锁
_post_lock() 善后工作
Lock():
pthread_mutex_lock()加锁
_post_lock() 善后处理工作
UnLock():
_pre_unlock() 提前处理工作
pthread_mutex_unlock()解锁
特别介绍:
class Locker {
Mutex &mutex;
public:
explicit Locker(Mutex& m) : mutex(m) {
mutex.Lock();
}
~Locker() {
mutex.Unlock();
}
};
Locker是定义于Mutex中的内部类,它在构造时执行加锁,析构时执行解锁
Mutex和Locker的比较:
共同点:
都表示互斥锁类型,用于保护共享代码区
不同点:
主要是使用地点不同前者可以用于各种简单或者复杂场合,而后者一般使用于简单的块场合中,如下例所示:
// Mutex
Mutex mutex;
mutex.lock();
do something
mutex.unlock();
// Locker
Mutex mutex;
if (cond) {
Mutext::Locker (mutex);
do something
}
condition variable
源码文件
- src/common/cond.h
class Cond
主要数据成员:
pthread_cond_t _c: 条件变量
Mutex *waiter_mutex: 保护条件变量的锁
主要成员函数:
Wait():
等待条件
确保同一个条件变量只使用一个互访锁保护
pthread_cond_wait()
由于pthread_cond_wait()会先执行一次解锁操作,返回前会执行一次加锁操作,
因此使用Mutex锁时保护条件变量时执行pthread_cond_wait()之前
必须进行_pre_unlock(),之后必须进行_post_lock().
WaitUntil():
等待直到未来的某个时间段
pthread_cond_timewait()
WaitInterval():
基于当前时间等待一段时间
WaitUntil()
SignalOne():
通知某个线程条件已经发生变化
pthread_cond_signal()
SignalAll():
通知所有线程条件已经发生变化
pthread_cond_broadcast()