1.2线程回收:
首先得知道线程的两个状态:
Joinable
Detached
简单理解,如果一个线程是joinable的状态,那么这样的线程,就必须使用pthread_join
来回收,否则程序结束时,线程所占用的资源不会释放,就会造成内存泄漏。
我们通常在主进程中会阻塞调用pthread_join
来等待我们的线程结束。
如果是Detached
状态的线程,那么在线程结束后,资源会自动释放,POSIX pthread线程库中,提供下面函数来让线程进入Detached
状态:
int pthread_detach(pthread_t thread);
设计中,考虑pthread_join
和pthread_detach
的特性,分别对成员函数join
和析构函数进程封装。
线程创建时默认情况情况下是Joinable状态。
2.线程封装
封装为一个C++ 类需要一些技巧:
1.Thread是没有拷贝构造和赋值语义的,因此也需要继承自boost::noncopyable
2.关于pthread_create的第三个参数(返回void*参数为void*的函数指针),因为成员函数会隐式包含this指针作为参数,所以加以static修饰。
3.对于pthread_create的第四个参数(void *arg作为线程参数),传入this指针方便线程调用成员函数。
4.使用join()成员函数封装pthread_join(),析构函数使用pthread_detach()处理。
5.设置run()成员函数为纯虚函数,子类重写run()方法。
class Thread : public boost::noncopyable
{
public :
Thread();
virtual ~Thread();//虚析构
void start();
void join();
virtual void run()=0;//纯虚函数
pthread_t getThreadId() const
{
return threadId_;
}
private:
//pthread_create()第三个参数是一个回调函数,void*为返回值和参数
static void *runInThread(void *arg);
pthread_t threadId_;
bool isRunning_;
};
//这里对成员函数进行定义,run()由于是纯虚函数,我们放到子类中重写:
Thread::Thread():isRunning_(false),threadId_(0){}//构造函数
Thread::~Thread()//析构函数
{
if(isRunning_)
{
CHECK(!pthread_detach(threadId_));//如果线程正在运行,则让其状态为detached
}
}
void *Thread::runInThread(void *arg)
{
Thread *pt =static_cast<Thread*>(arg);//arg即为this指针
pt->run();//调用run方法
return NULL;
}
void Thread::start()
{
CHECK(!pthread_create(&threadId_,NULL,Thread::runInThread,this));//创建线程
isRunning_=true;
}
void Thread::join()
{
assert(isRunning_);
CHECK(!pthread_join(threadId_,NULL));//回收线程
isRunning_=false;
}