首页 > 技术文章 > c++ 封装线程库 2

zhangkele 2018-07-25 20:44 原文

1.2线程回收:

首先得知道线程的两个状态:

Joinable 
Detached

简单理解,如果一个线程是joinable的状态,那么这样的线程,就必须使用pthread_join来回收,否则程序结束时,线程所占用的资源不会释放,就会造成内存泄漏。

我们通常在主进程中会阻塞调用pthread_join来等待我们的线程结束。

如果是Detached状态的线程,那么在线程结束后,资源会自动释放,POSIX pthread线程库中,提供下面函数来让线程进入Detached状态:

int pthread_detach(pthread_t thread);

设计中,考虑pthread_joinpthread_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;
}

 

推荐阅读