在單獨執行緒中執行物件成員函式 (轉)

worldblog發表於2007-12-04
在單獨執行緒中執行物件成員函式 (轉)[@more@]問題的提出:
  實際上所有執行緒都是用來處理C的,而不是C++類成員函式。標準庫中提供一個函式,這個函式以回撥函式指標作為執行緒的程式碼並在單獨的執行緒中回撥函式。問題是在這樣的執行緒庫中不能建立執行成員函式的執行緒;只能使用普通的函式。因此,下列程式碼是失敗的:

// 啟動執行緒庫函式的執行緒
int thr_create (void (*pf)(), void* prm, thread_t* pth);

#include "class1.h"

int func (void *param )
{
thread_t t1;
// 下列呼叫導致錯誤: "Cannot convert 'void (class1::*)()' to 'void (*)()'"
// 意思是不能轉換型別
return thr_create ( &class1::some_method, param, &t1);
}

  函式thr_create()需要回撥函式的地址,void* 作為地址引數被傳遞到回撥函式,同時傳遞的引數還有thread_t變數的指標(有關回撥函式和函式指標的概念參見VC知識庫中另外的文章)。

  上面的程式碼之所以編譯失敗是因為傳遞到thr_create()的第一個引數是類class1的成員函式指標,而不是普通函式指標。從概念上講,普通函式和類成員函式是兩個完全不同的事情。即使進行強制型別轉換也不行。那麼如何解決這個問題呢?

方法一:使用靜態成員函式

  第一個解決方法是使回撥成員函式為靜態。因為靜態成員函式不帶隱含式引數“this”。因此,可以將其引數中的地址當作是普通函式的指標來使用。如果要從靜態成員函式中訪問物件的資料成員,顯式傳入物件的地址即可。例如:

class
{
private:
int x;
public:
int get_x();
static void func(Hack * pthis); // 靜態成員函式
void func2(); // 非靜態成員函式
};

void Hack::func(Hack * pthis)
{
int y = pthis->get_x(); // 訪問物件的資料成員
}

  這個方法在大多數情形下都能行得通,但有時候成員函式不能宣告為靜態,也就是說成員函式是虛擬函式或者正在使用不能修改的第三方類。遇到這種情況時,用方法一解決問題就比較難了。

方法二:處理非靜態成員函式

  假設需要在單獨的執行緒中呼叫類Hack的非靜態成員函式func2()。不用直接傳遞成員函式的地址到thr_create(),宣告一個帶 void* 引數的普通函式intermediary(void*),然後呼叫它:

void intermediary(void*);

接著建立一個結構,結構定義如下:

struct A
{
Hack * p; //類物件指標
void (Hack::*pmf)(); // 成員函式指標
};

  建立一個結構例項,用希望的物件地址和成員函式地址填充結構(有關詳細的成員函式指標內容請參見VC知識庫中的其它文章)。

A a; // 結構例項
Hack h; // 建立物件
//填充結構
a.p = & h; 
a.pmf = &Hack::func2; // 取成員函式地址

現在回過頭來實現intermediary()函式:

void intermediary(void* ptr)
{
A* pa=static_cast < A* > (ptr); // 強制轉換 p 為 A* 
Hack* ph=pa->p; // 從A中析取Hack物件地址
void (Hack::*pmf)()=pa->pmf; // 析取 ptr 到成員函式
(ph->*pmf)(); // 呼叫成員函式
}

最後將intermediary()的地址傳遞到thr_create():

thr_create (intermediary, (void*) &a, &t1 );

thr_create()呼叫函式intermediary()並將A的地址傳遞給它。intermediary()再從其指標引數中展開結構A並呼叫希望的成員函式。這種間接方式的處理可以地在單獨執行緒中啟動成員函式,即便是執行緒庫不支援成員函式。如果需要呼叫不同類的不同成員函式,可以將結構A轉換成類别範本,將函式intermediary()轉換成函式模板。從而編譯器便會自動產生大多數樣板程式碼。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988405/,如需轉載,請註明出處,否則將追究法律責任。

相關文章