boost学习笔记一: 使用boost::shared_ptr做为线程的参数

11877阅读 3评论2008-03-25 yulc
分类:C/C++

使用linux下的线程创建函数pthread_create已久,在传递给它void*型的入口参数时,总是两种方式:
1. 在堆中创建,传入参数指针至线程中,由线程内部释放或等待线程退出后再释放;
2. 不在堆中创建或使用全局变量;

虽然在各种书上提及这种方式的种种不足,但我一直用得还挺好.主要就是注意资源的释放就成,毕竟这种低层的API能给程序员最大的灵活性,所谓有空间才能发挥嘛.但不可否认的是,站得更高是会看得更远.一些设计确实能让代码变得更加简洁,并且不用关注太多低层的细节.其实我一直觉得细节很重要,但要会取舍.


看看以下几个类如何能让代码更优雅:
boost::shared_ptr
boost::bind
boost::thread


作为比较,以下是linux下标准的创建线程的例子:



/*
  build args:
  -lpthread
*/


#include <pthread.h>
#include <iostream>
#include <string>

using namespace std;

class B
{
public:
    B() {cout << "construct B;" << endl;}
    void out() { cout << "B::out();" << endl; }
    ~B(){ cout << "destroy B;" << endl;}
};

void* fun2(void* p)
{
    B* pb =(B*)p;
    pb->out();
    sleep(3);
    delete pb; // 在这里释放主线程中创建的对象.
}

void fun()
{
    pthread_attr_t ta;
    pthread_attr_init(&ta);
    pthread_t tid;

    B *pb = new B(); // 创建B的对象作为线程的参数
    pthread_create(&tid, &ta, (void*(*)(void*))fun2, (void*)pb);
    pthread_join(tid, NULL);
}

int main()
{
    fun();
    cout << "FINISH" << endl;
}



如果用上shared_ptr,就不再需要在线程中来删除资源了.因为当引用计数为0时,shared_ptr会自动的销毁掉内含的指针.



/*
  build args(boost 1.34.1 installed /usr/local/):
  -I/usr/local/include/boost-1_34_1 -L/usr/local/lib -lboost_thread-gcc41-mt
*/



#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>

#include <iostream>
#include <string>

using namespace std;

class B
{
public:
    B() {cout << "construct B;" << endl;}
    void out() { cout << "B::out();" << endl; }
    ~B(){ cout << "destroy B;" << endl;}
};

void* fun2(void* p)
{
    /*
       转呀转就把原类型转回来了.
    */

    boost::shared_ptr<B> pb = *(boost::shared_ptr<B>*)(p);
    pb->out();

    sleep(10);
    
    // 注意在这里就不再需要delete
}



void fun()
{
    /*
       boost中的引用指针计数器(shared_ptr),这个shared_ptr对象内含B的对象指针,
       但由于fun2()函数的参数是void*,所以还需要取这个对象的地址传入.
       fun2()其实可以直接用boost::shared_ptr类型,就无须这样麻烦的转换,不过这样的话,就不能支持任意类型了.
    */

    boost::shared_ptr<B> pb(new B());
        
    /*
       这里不再需要关注thread的创建细节;
       boost::bind设计得太巧妙了;
    */

    boost::thread bthread(boost::bind(fun2, (void*)&pb));

    bthread.join();
}


int main()
{
    fun();
    cout << "FINISH" << endl;
}


上面的类型转换有点恶心,不过好在shared_ptr也是允许内部指针的类型继承的,好绕口.

还是看以下代码吧,B类由A类派生而来.所以boost::shared_ptr这个类型,可以传递boost::shared_ptr对象,并且由于shared_ptr重载了"->"符号,所以直接就可以访问B的成员了.




#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <string>


using namespace std;


class A
{
public:
        virtual void out() {cout << "A::out();" << endl;}
};

class B : public A
{
public:
    B() {cout << "construct B;" << endl;}
    virtual void out() { cout << "B::out();" << endl; }

    ~B(){ cout << "destroy B;" << endl;}
};



/*
  fun2 可以接收任何A类以及从A派生的类的shared_ptr对象.
  这样做,勉强也可算是支持任意类型了,因为只要传递的参数是从A派生即可.
*/

void* fun2(boost::shared_ptr<A> pa)
{
    // 不再需要任何转换,直接访问其子类的虚方法了.

    pa->out();
    sleep(10);
}

void fun()
{
    /*
       代码确实很简洁了.
    */

    boost::shared_ptr<B> pb(new B());
    boost::thread bthread(boost::bind(fun2, pb));

    bthread.join();
}

int main()
{
    fun();
    cout << "FINISH" << endl;
}



上一篇:测试在多线程下操作sqlite内存数据库
下一篇:TCP非阻塞的accept()返回的会话的属性.

文章评论