| 導購 | 订阅 | 在线投稿
分享
 
 
 

在單獨線程中執行對象成員函數

2008-06-01 01:55:05  編輯來源:互聯網  简体版  手機版  移動版  評論  字體: ||
 

問題的提出:

實際上所有線程都是用來處理C函數的,而不是C++類成員函數。標准庫中提供一個API函數,這個函數以回調函數指針作爲線程的執行代碼並在單獨的線程中調用回調函數。問題是在這樣的線程庫中不能創建執行對象成員函數的線程;只能使用普通的函數。因此,下列代碼是失敗的:

// 啓動線程庫函數的線程

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 Hack

{

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()轉換成函數模板。從而編譯器便會自動産生大多數樣板文件代碼。

 
問題的提出:   實際上所有線程都是用來處理C函數的,而不是C++類成員函數。標准庫中提供一個API函數,這個函數以回調函數指針作爲線程的執行代碼並在單獨的線程中調用回調函數。問題是在這樣的線程庫中不能創建執行對象成員函數的線程;只能使用普通的函數。因此,下列代碼是失敗的: // 啓動線程庫函數的線程 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 Hack { 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()轉換成函數模板。從而編譯器便會自動産生大多數樣板文件代碼。
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
王朝網路微信公眾號
微信掃碼關註本站公眾號 wangchaonetcn
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有