提供线程类和线程同步类,基于pthread实现,包括以下类:

Thread:线程类,构造函数传入线程入口函数和线程名称,线程入口函数类型为void(),如果带参数,则需要用std::bind进行绑定。线程类构造之后线程即开始运行,构造函数在线程真正开始运行之后返回。

线程同步类(这部分被拆分到mutex.h)中:

Semaphore: 计数信号量,基于sem_t实现
Mutex: 互斥锁,基于pthread_mutex_t实现
RWMutex: 读写锁,基于pthread_rwlock_t实现
Spinlock: 自旋锁,基于pthread_spinlock_t实现
CASLock: 原子锁,基于std::atomic_flag实现


线程模块总体比较简单,在对pthread相关的接口有一定了解的情况下,参考源码应该不难理解,这里说几个重点:

1. 为什么不直接使用C++11提供的thread类。按sylar的描述,因为thread其实也是基于pthread实现的。并且C++11里面没有提供读写互斥量,RWMutex,Spinlock等,在高并发场景,这些对象是经常需要用到的,所以选择自己封装pthread。

2. 关于线程入口函数。sylar的线程只支持void(void)类型的入口函数,不支持给线程传参数,但实际使用时可以结合std::bind来绑定参数,这样就相当于支持任何类型和数量的参数。

3. 关于子线程的执行时机。sylar的线程类可以保证在构造完成之后线程函数一定已经处于运行状态,这是通过一个信号量来实现的,构造函数在创建线程后会一直阻塞,直到线程函数运行并且通知信号量,构造函数才会返回,而构造函数一旦返回,就说明线程函数已经在执行了。

4. 关于线程局部变量。sylar的每个线程都有两个线程局部变量,一个用于存储当前线程的Thread指针,另一个存储线程名称,通过Thread::GetThis()可以拿到当前线程的指针。

5. 关于范围锁。sylar大量使用了范围锁来实现互斥,范围锁是指用类的构造函数来加锁,用析造函数来释放锁。这种方式可以简化锁的操作,也可以避免忘记解锁导致的死锁问题,以下是一个范围锁的示例和说明:

sylar::Mutex mutex;

{
	sylar::Mutex::Lock lock(mutex); // 定义lock对象,类型为sylar::Mutex::Lock,传入互斥量,在构造函数中完成加锁操作,如果该锁已经被持有,那构造lock时就会阻塞,直到锁被释放
	//临界区操作
	...
	// 大括号范围结束,所有在该范围内定义的自动变量都会被回收,lock对象被回收时触发析构函数,在析构函数中释放锁
}