![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?5a7ff87)
環境は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++のメンバ関数をマルチスレッド関数としたい場合はどの様に書けばよいのでしょうか・・?
No.2ベストアンサー
- 回答日時:
こんにちは。
メンバ関数からスタティックメンバ関数のアドレスと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;
}
beginthreadってthisポインタが渡せたんですね!!
MSDNでarg_listってなんのこっちゃと思ってたら・・
本当にありがとうございました!
No.3
- 回答日時:
いろいろやり方がありますが、最も自由度が高く、
一般的なのはスレッド関数に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;
}
この方法では、あまり細かいコードを書かなくて済みますし
初心者にも直感的にわかりやすい点がお勧めです。
MFCには標準でthisを渡せる関数があるんですね~。
ちょっと私の環境ではMFCの導入が厳しいので
次回なにか作るときにぜひ利用してみようと思います。
ありがとうございました!
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# スタックフレームの消滅 6 2023/05/20 12:33
- C言語・C++・C# c言語の問題です 課題1 (二分探索木とセット) 大きさ size の配列 array を考える。す 2 2023/01/10 21:08
- C言語・C++・C# 関数名 (type *) 1 2022/03/28 10:55
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# Windows Formアプリからコンソールを呼び出して文字を出力させたい 8 2023/05/09 10:53
- Java java final 1 2022/06/10 22:49
- C言語・C++・C# leetcode 155 minstack 1 2022/05/07 16:43
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
戻り値を返す関数の前に(void)...
-
多重定義が起きている?--lnk20...
-
静的でないメンバ関数の呼び出...
-
C++にてtemplateで受け取った任...
-
DLLの関数呼び出しで引数がある...
-
既定のコンストラクタがありま...
-
(void)0 はどんな意味ですか
-
コールバックって・・・
-
C# Controls.Addで動的に配置し...
-
int main()、void main()、void...
-
組み込みマイコン
-
【gcc・cygwin】multiple defin...
-
VC++でGetKeyboardStateがうま...
-
コンパイルエラー: LNK2001
-
RENDERFILEについての質問です
-
C#でトーンカーブの作成
-
void main()って誰が最初?:AN...
-
クラス間でのクラスの共有?
-
マルチメディアタイマー
-
メンバ関数(メソッド)をマル...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
既定のコンストラクタがありま...
-
【gcc・cygwin】multiple defin...
-
Notepad++の関数リスト表示の変...
-
戻り値を返す関数の前に(void)...
-
ArduinoでMouse関数を使用して...
-
C++にてtemplateで受け取った任...
-
int main()、void main()、void...
-
多重定義が起きている?--lnk20...
-
C# KeyDownイベントでショート...
-
静的でないメンバ関数の呼び出...
-
VC++でGetKeyboardStateがうま...
-
C# Controls.Addで動的に配置し...
-
gcc: incompatible pointer type
-
void*型の配列について
-
const_castのつかいどころを教...
-
C言語 ① 5秒間 1秒間隔で点滅を...
-
(void)0 はどんな意味ですか
-
TimerProc コールバック関数を...
-
H8マイコンのシリアル通信につ...
-
DLLの関数呼び出しで引数がある...
おすすめ情報