staticでないクラスメンバ関数を_beginthreadで実行させる方法。
クラスメンバ関数を_beginthreadする場合、メンバ関数はstaticでなければならない。
非staticなメンバ関数を実行したい場合は、以下のようにstaticでなメンバ関数をかませて実行する。
// スレッドを発生されるクラス class Test { :private HANDLE thread; // スレッドハンドル // スレッド開始 void threadStart(){ thread = (HANDLE) _beginthread( &test::executeLauncher, // ランチャを起動 0, this); } // ランチャ static void executeLauncher(void* args){ // 無理やりtest*型にキャストして、本命の処理を実行する。 reinterpret_cast<test*>(args)->execute(); } // 本命の処理(非staticメンバ変数) void execute(){ … } }; main(){ Test test = new Test(); // スレッドで、staticではないメンバ変数execute()が実行 test->threadStart(); }
メンバ関数ポインタがstaticでなければならない理由。
MSDNによると、
uintptr_t _beginthread( void( *start_address )( void * ), unsigned stack_size, void *arglist );
start_address
新規スレッドの実行を起動するルーチンの開始アドレス。_beginthread の呼び出し規約は __cdecl または __clrcall
関数呼び出し規約
VC++での関数呼び出し規約は、__cdecl、__stdcall、__clrcall、__thiscall等がある。
それぞれの詳細は、こちらを参照→二流プログラマの三流な日常: 関数呼び出しの内部を理解する(2)によると…
__cdecl
一般的な関数呼び出し規約。普通の関数ポインタはこれで呼び出す。
___stdcall
WindowsAPI用の関数呼び出し規約。
__clrcall
CLR用の関数呼び出し規約
まとめ
メンバ関数の種類 | 呼び出し規約 |
---|---|
staticのメンバ関数 | __cdecl |
非staticのメンバ関数 | __thiscall |
_beginthreadの仕様では、呼び出し規約が__cdeclの為、staticのメンバ関数しか呼び出せない。
その為、非staticのメンバ関数を呼び出すには、上記のような小細工が必要。
参考サイトとか
ロベールのC++教室 - 第57章 メンバ関数ポインタ天国
ここ、良質な記事が多いのになんで閉鎖しちゃったんだろ。残念。
2007/7/23追記
コメントに頂いたように、ロベールのC++教室 さんは移転していただけの様です。
リンク修正しましたー。
2008/4/3追記
関数呼び出し規約の勘違いを修正。