1. 程式人生 > >beginthreadex()函式在建立多執行緒傳入回撥函式時,好像只能傳入全域性函式或類的靜態成員函式,請問能不能傳入類的成員函式呢(非靜態)?

beginthreadex()函式在建立多執行緒傳入回撥函式時,好像只能傳入全域性函式或類的靜態成員函式,請問能不能傳入類的成員函式呢(非靜態)?

C++類成員函式直接作為執行緒回撥函式2009年06月01日 星期一 17:01我以前寫執行緒時要麼老老實實照著宣告寫,要麼使用C++類的靜態成員函式來作為回撥函式,經常會因為執行緒程式碼而破壞封裝.之前雖然知道類成員函式的展開形式,但從沒想過利用過它,昨天看深入ATL時無意中學會了這一招:) 

類成員方法是一個比較特殊的函式,它在編譯時會被轉化成普通函式,比如有TMyClass類:
class TMyClass{
    void Func();
};

這個TMyClass::Func最終會轉化成 void Func(TMyClass *this); 也就是說在原第一個引數前插入指向物件本身的this指標。

我們可以利用這個特性寫一個非靜態類成員方法來直接作為執行緒回撥函式,先看_beginthread函式的定義:
unsigned long _RTLENTRY _EXPFUNC _beginthread (void (_USERENTRY *__start)(void *),unsigned __stksize, void *__arg);
其中的第一個引數就是作為執行緒執行主體的回撥函式。它的原型是:void Func(void *),這個void*引數是作為自定義資料傳入的。對比一下上面所說的TMyClass::Func的最終形式,它正好可以符合這裡的要求。

現在做個實驗:
#include <stdio.h>
#include <process.h>

class TMyClass{
    int m_nCount;
    int m_nId;
public:
    TMyClass(int nId,int nCount)
        :m_nId(nId),m_nCount(nCount)
    {
    }

    void _USERENTRY ThreadProc()            // 類成員方法
    {
        for(int i=0; i<m_nCount; i++)       // 根據m_nCount成員列印一排數字
        {
            printf("Class%d : %d\n",m_nId,i);
        }
    }
};

int main(int argc, char* argv[])
{
    union {                                // 聯合類,用於轉換類成員方法指標到普通函式指標(試過編譯器不允許在這兩種函式之間強制轉換),不知道有沒有更好的方法。
        void (_USERENTRY *ThreadProc)(void *);
        void (_USERENTRY TMyClass::*MemberProc)();
    } Proc;                                // 儘管聯合裡的兩種函式型別現在看起來有很大不同,但它們的最終形式是相同的。

    TMyClass MyClass1(1,10),MyClass2(2,5); // 產生兩個TMyClass物件

    Proc.MemberProc = &TMyClass::ThreadProc;   // 轉換,Proc.ThreadProc就是對應的普通函式指標了

    _beginthread(Proc.ThreadProc,4096,&MyClass1);   // 開始執行緒,這裡的Proc.ThreadProc實際上是TMyClass::ThreadProc, 它要的this指標是我們給的&MyClass1。
    _beginthread(Proc.ThreadProc,4096,&MyClass2);
    system("pause");
    return 0;
}

執行!神奇吧?:-)

其實不止執行緒回撥函式,其實只要是形如Func(void*,...)的回撥函式都可以用這種方法直接使用類成員方法。(前提是第一個void*是自定義資料,也就是說它不能有其它功能)。

轉自:http://blog.csdn.net/waiting4you/archive/2007/12/29/2000796.aspx