メンバ関数を_beginthreadex()使ってマルチスレッドにする

あるメンバ関数をbeginthreadex()を使ってマルチスレッド化するためには、マルチスレッド化したいメンバ関数を一度ラップする。_beginthreadex()には以下の呼び出し規約がある。

beginthread,beginthreadex

新しいスレッドの実行を開始するルーチンの開始アドレス。
_beginthread では、__cdecl (ネイティブ コードの場合) または __clrcall (マネージ コードの場合) の呼び出し規約を使用します。
_beginthreadex では、__stdcall (ネイティブ コードの場合) または __clrcall (マネージ コードの場合) の呼び出し規約を使用します。

MSDN

また、スレッド完了ステータスを受けるため、メソッドの返値の型をunsigned intにして、かつ__stdcallを付与しないと型が一致しないとコンパイラに怒られる(スレッドに渡す関数は、staticでないといけない)。というわけで、スレッド化するメンバ関数の返値の型はunsigned int __stdcall(またはWINAPI)として定義する必要があるが、staticでないメンバ関数をマルチスレッドにするにはどうしたらよいか。

実装

例えば、Render()をマルチスレッド化する場合、外部からはExecRendering()メソッドからレンダリングスレッドを開始するが、クラス内ではスレッド化したいメンバ関数(Render())をBeginRendering()でラップしておく。beginthreadex()には、自身のインスタンスへのポインタをラップしたメンバ関数へと渡す。それを用いて、実行したいメンバ関数にアクセスする。

#include <windows.h>

Class VideoRender
{
public :
  VideoRender();
  virtual ~VideoRender();
  void ExecRendering();
private :
  HANDLE hRenderThread;
  unsigned int WINAPI BeginRendering(void *obj);
  int Render();
};

VideoRender::VideoRender()
{
  hVideoRenderThread = NULL;
}

VideoRender::~VideoRender()
{
  WaitForSingleObject(hVideoThread, INFINITE);
  CloseHandle(hVideoThread);
}

void VideoRender::ExecRendering()
{
  hRenderThread = <span class="deco" style="color:#FF0000;">(HANDLE)_beginthreadex(NULL, 0, BeginRendering, this, NULL)</span>;  
}

unsigned int WINAPI VideoRender::BeginRendering(void *obj)
{
  reinterpret_cast<VideoRender *>(obj)->Render();
  return 0;
}

// マルチスレッド化するメンバ関数
int VideoRender::Render()
{
  // 実行したい処理
}