「お昼の放送」の思い出

環境はWinXPでVisual Studio 2005を使用しています。
C言語で関数をマルチスレッド化するにはこんな感じでOKでした。

// マルチスレッド関数
void Thread( void * )
{
}

void MainFunc()
{
  (HANDLE)_beginthread( Thread, 0, NULL );
}



こんな風にスレッド関数をC++のメソッドに変えてうまくいくかと思い

class Test_c {
public:
  void Thread( void * );
} ;

// マルチスレッド関数
void Test_c::Thread( void * )
{
}

void MainFunc()
{
  Test_c t t;
  (HANDLE)_beginthread( t.Thread, 0, NULL );
}

とするとエラーが出てきてしまい、コンパイルが通りませんでした。
C++のメンバ関数をマルチスレッド関数としたい場合はどの様に書けばよいのでしょうか・・?

A 回答 (3件)

 こんにちは。



 メンバ関数からスタティックメンバ関数のアドレスとthisポインタを渡してスレッドを起動するのが手っ取り早いです。
 スレッドに飛び込んだら、其のままパラメータをTest_c*にキャストして、メンバ関数側へ迂回出来ます。
 その他、クリティカルセクション等は、外回りで必要に応じてするか、メンバ関数内でするか等、色々有るのですが・・・。
 アラも有りますが、取り敢えずは参考程度に。

#include<windows.h>
#include<mmsystem.h>
#include<process.h>
#include<stdio.h>

#pragma comment(lib, "winmm.lib")

//クリティカルセクション
class CCS
{
CRITICAL_SECTION cs;
public:
CCS(){::InitializeCriticalSection(&this->cs);}
~CCS(){::DeleteCriticalSection(&this->cs);}

CRITICAL_SECTION* get() const { return (CRITICAL_SECTION*)&this->cs; }
};
//排他クラス
class CLock
{
const CCS& rccs;
public:
CLock(const CCS& r) : rccs(r){::EnterCriticalSection(rccs.get());}
~CLock(){::LeaveCriticalSection(rccs.get());}
};
//テストクラス
class Test_c
{
enum { ThreadCount = 2 };
HANDLEarrhThread[ThreadCount];
CCSccs;
intvalue;
//マルチスレッド関数(計算)メンバ関数へ転送
static void ThreadCalc(void* p)
{
Test_c* pTest = (Test_c*)p;
pTest->calc();
}
//マルチスレッド関数(表示)メンバ関数へ転送
static void ThreadPrint(void* p)
{
Test_c* pTest = (Test_c*)p;
pTest->print();
}
//メンバ関数(計算)
void calc()
{
::printf("%s\n", "計算開始");
const DWORD dwStartTime = ::timeGetTime();
//1秒間計算する
while(::timeGetTime() - dwStartTime <= 1000)
{
CLock lock(this->ccs);
++this->value;
::Sleep(16);
}
::printf("%s\n", "計算終了");
::_endthread();
}
//メンバ関数(表示)
void print()
{
::printf("%s\n", "表示開始");
const DWORD dwStartTime = ::timeGetTime();
//1.5秒間表示する
while(::timeGetTime() - dwStartTime <= 1500)
{
CLock lock(this->ccs);
::printf("%d\n", this->value);
::Sleep(16);
}
::printf("%s\n", "表示終了");
::_endthread();
}
public:
//全てがシグナルになるまで待つ
static void Wait(Test_c& t)
{
while(1)
{
const DWORD dwResult = ::WaitForMultipleObjects(ThreadCount, t.arrhThread, TRUE, INFINITE);
if(dwResult >= WAIT_OBJECT_0 && dwResult <= WAIT_OBJECT_0 + ThreadCount - 1)
break;
}
}
Test_c() : ccs(), value(0)
{
for(int i = 0; i < ThreadCount; ++i)
arrhThread[i] = NULL;
}
void start()
{
this->arrhThread[0] = (HANDLE)::_beginthread(&Test_c::ThreadPrint, 0, this);
this->arrhThread[1] = (HANDLE)::_beginthread(&Test_c::ThreadCalc, 0, this);
}
void close()
{
for(int i = 0; i < ThreadCount; ++i)
{
::CloseHandle(arrhThread[i]);
arrhThread[i] = NULL;
}
}
};
//お試し
int main()
{
TIMECAPS tc = {0};
::timeGetDevCaps(&tc, sizeof(tc));
::timeBeginPeriod(tc.wPeriodMin);
Test_c test;
test.start();
Test_c::Wait(test);
::timeEndPeriod(tc.wPeriodMin);
return 0;
}
    • good
    • 0
この回答へのお礼

beginthreadってthisポインタが渡せたんですね!!
MSDNでarg_listってなんのこっちゃと思ってたら・・
本当にありがとうございました!

お礼日時:2009/02/27 21:36

いろいろやり方がありますが、最も自由度が高く、


一般的なのはスレッド関数にthisを渡す方法ですね。
class FOO{
void TH_Start(){
::AfxBeginThread( ThFunc, this,
THREAD_PRIORITY_NORMAL, 0, 0, NULL);
}
void TH_CallBack(){
   // ここが実際のスレッドのメインとなります。
}
}

スレッド関数は渡されたクラスオブジェクトの
クラスコールバックを呼ぶたけです。何もしません。

UINT ThreadFunc( PVOID p_obj){// thisが渡される
FOO *p_foo = ( FOO *)p_obj;
p_foo->TH_CallBack();// クラスコールバックを呼ぶ
return 0;
}

この方法では、あまり細かいコードを書かなくて済みますし
初心者にも直感的にわかりやすい点がお勧めです。
    • good
    • 0
この回答へのお礼

MFCには標準でthisを渡せる関数があるんですね~。
ちょっと私の環境ではMFCの導入が厳しいので
次回なにか作るときにぜひ利用してみようと思います。
ありがとうございました!

お礼日時:2009/02/27 21:32

class Test_c {


public:
  static void Thread( void * );
} ;
とすれば呼び出せます。
ただし、やると分りますが別のワナが・・・。thisが使えません。
    • good
    • 0
この回答へのお礼

確かにそのようですね・・。ありがとうございました。。
こういうのは本当に面倒ですね・・

お礼日時:2009/02/27 21:10

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報