使用boost::shared_ptr做爲線程的參數

使用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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章