• ベストアンサー

メンバ関数(メソッド)をマルチスレッドにしたい

環境は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 }; HANDLE arrhThread[ThreadCount]; CCS ccs; int value; //マルチスレッド関数(計算)メンバ関数へ転送 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; }

RockmanX
質問者

お礼

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

その他の回答 (2)

回答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; } この方法では、あまり細かいコードを書かなくて済みますし 初心者にも直感的にわかりやすい点がお勧めです。

RockmanX
質問者

お礼

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

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.1

class Test_c { public:   static void Thread( void * ); } ; とすれば呼び出せます。 ただし、やると分りますが別のワナが・・・。thisが使えません。

RockmanX
質問者

お礼

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

関連するQ&A

  • 静的でないメンバ関数の呼び出しが正しくありません

    コンパイル時に「静的でないメンバ関数の呼び出しが正しくありません」となってしまいます。 普通の関数からメンバー関数を呼び出すには、どう記述すればいいのでしょうか? void MyDataHandler(sFrameOfData* FrameOfData) { CFrrjiftestDlg::sndrobot();  ← ここがコンパイルエラー } void CFrrjiftestDlg::sndrobot() { いろいろ記述 } //*** 以下、ヘッダー class CFrrjiftestDlg : public CDialog { DECLARE_DYNAMIC(CFrrjiftestDlg); friend class CFrrjiftestDlgAutoProxy; // Construction public: CFrrjiftestDlg(CWnd* pParent = NULL); // standard constructor virtual ~CFrrjiftestDlg(); void msubInit(); void sndrobot();   ←ここで宣言 };

  • マルチスレッド化。

    今とても大きな配列を使用し、長時間処理をするプログラムを組んでいます。元々処理時間に1時間を要するプログラムを2分で処理を完了するまでに仕上げました。 しかし、探究心はおさまらずもう少し高速化に挑みたいと考えています。 過去に「猫でもわかる」のSDK第1章と2章を学び、マルチスレッドのプログラムをSDKで組んだことがあります。それを利用してマルチスレッド化を実現したいと考えています。 言語はCでVisualStudio2005を使用しています。 *疑問1   SDKの場合WinMain関数とプロシージャからの実行で_beginthread関数を記述すれば処理が開始されます。 Cでもmain関数内に記述すれば、SDKと同様に処理できるのでしょうか? *疑問2 _beginthread関数の引数に関してです。 第1引数にvoid型のスレッド関数、第2引数に0?、そして第3引数にはスレッド関数に渡すデータの引数を記述すると把握しているのですが、渡したいデータは複数あり、***型と**型、それに変数を数個とスレッド関数に渡したいデータだらけなのですが、どのように記述すればよいでしょう? *疑問3 2つのスレッドを作成しようと考えていますが、その2つのスレッドで1つの大きな配列を共有して処理したいと考えています。 そのため、スレッド間の同期が必要になるわけですが同期の種類にもクリティカルセクションやミューテックス、イベントと豊富でどれを使用すれば良いのか迷ってしまいます。厳密に同期を取り処理をするにはイベントが一番良いと考えています。 これらの疑問に答えられる方はアドバイスをよろしくお願いします。

  • (マルチスレッド)_beginthreadexに複数の引数を渡す

    現在プログラムでマルチスレッドをやろうとしているのですが、 マルチスレッドの関数に数値や配列などの引数を渡すことは可能でしょうか? MSDNで調べてみると、_beginthreadex関数の4番目のNULLのところに引数リストを 指定できるとあったのですが、その意味が良くわかりませんでした。 以下のプログラムの場合にマルチスレッドに変数a, b, cを引数として渡したい場合は どのように書けばいいのでしょうか? #include <stdio.h> #include <windows.h> #include <process.h> unsigned WINAPI MyThread( void *lpx ){ while (1) { printf("スレッド実行中\n"); Sleep(1000); } return 0; } void main(){ // スレッドに渡したい変数の宣言 int a = 128; int b = 256; int c = 512; // スレッドIDの宣言 DWORD thID; // マルチスレッドの開始 (HANDLE)_beginthreadex( NULL, 0, &MyThread, NULL, 0, (unsigned int*)&thID ); // ループ while (1) { printf("メイン関数実行中\n"); Sleep(2000); } }

  • C# マルチスレッドにおける例外処理

    下記のようなデリゲートを利用したマルチスレッドのプログラムを組みました。 しかし、マルチスレッド内で例外がおきても、正常にプログラムが終了してしまいます。 (try-catchでも例外を捕捉できません) マルチスレッドプログラムにおいて、例外を捕捉するにはどうすれば、いいのでしょうか? using System; using System.Threading; class Class1 { delegate void delg(); public static void Main() { delg d = new delg(multi); d.BeginInvoke(new AsyncCallback(call), null); //マルチスレッド開始 System.Threading.Thread.Sleep(500); //マルチスレッドで例外を強制的に投げているので、 //ここまでたどり着く前にアプリケーションが落ちるはず。 //しかし、実際には正常終了。 Console.WriteLine("メインメソッド 正常終了"); } public static void multi() { Console.WriteLine("マルチスレッドで実行中"); throw new Exception(); //例外を強制的に投げる。 } public static void call(IAsyncResult ar) { Console.WriteLine("コールバックメソッド実行"); } }

  • C++マルチスレッド処理について

    こんにちは 現在スレッドを作成して,マルチスレッド処理をしようとしているのですが, 全然理解できないので皆様のお力をお貸し下さい。 やりたい事は, (1) メインスレッドからスレッド1を作成。 (2) スレッド1では,ひたすらファイルなどからデータを取得させる。(読み込めなくなるまで) (3) メインスレッドでは,時々スレッド1を止めて,再度処理を続行させたい。 class Sample { public: // Sampleオブジェクト作成,同時にスレッド1を作成 Sample* create(); // スレッド1を止めて,再度動かす void process(); private: // この関数をスレッド1で処理させる // 内部では,読み込めなくなるまで無限ループ? void get(); }; スレッドに関してはイメージが湧くのですが, mutex (必要ですか?) に関しては一向に理解できません。 何を排他制御するのでしょうか。オブジェクト? 関数? 複雑ではなさそうなのですが,今までシングルスレッドの処理のみ書いていたため ピンときません。 よろしくお願い致します。

  • 関数の引数でクラスを作成して受け渡す機能について

    C++に以下のような機能はありますか? ・関数やメソッドの呼び出し引数の中でクラスなどを一時定義してそれを受け渡す仕組み 確か、Javaにこんなのがあったと記憶していますが、C++にはあるのでしょうか? ↓は概念的なものですので正しいコードではありません。 大雑把なコードにすると↓のような感じの機能なのですが名前が分かりません・・。 名前とその仕組みがあればそれについて教えていただけたらと思います。 class Test_c { public:   int t;   Test_c( int x ){     t = x;   } } ; void test( Test_c tc ){ } int main(){   test( new Test_c( 10 ) ); }

  • Servletとマルチスレッド

    以下のようにServlet側のある部分をマルチスレッドで実装しましたが、まったく速くなりません。Servletはもともとマルチスレッドで動いてるから速くならないのか、それとも自分のソースがおかしいのかわかりません、どなたかおしえていただけますか? public class ***Servlet exends ** { private void hogehoge(){ HogeThread hoge1 = new HogeThread(); Thread th1 = new Thread(hoge, ""); th1.start(); HogeThread hoge2 = new HogeThread(); Thread th2 = new Thread(hoge, ""); th2.start(); } } class HogeThread implements Runnable { public void run() { // hogehoge } }

    • ベストアンサー
    • Java
  • C++ シングルトン マルチスレッド

    標準C++でシングルトンを実装したいのですが。 class Singleton{ public: static Singleton* getInstance(){ if (_instance == NULL){ //スレッドAがこの時点で、スレッドBがNULLチェックすると破綻する _instance = new Singleton(); } return _instance; } private: Singleton(); static Singleton* _instance; }; マルチスレッドになると上記のパターンで破綻するといわれどうしたものかと考えております。 static Singleton* _instance = new Singleton(); と出来れば解決なのですが 「static const int データメンバ以外をクラス内で初期化することはできません」 とのことでそれもできず。 どのようにすればよいでしょうか。

  • Androidのマルチスレッド処理の開始タイミング

    組み込みボード上にAndroidOSをのせ、 その上でRS232C通信制御するプログラムを作成しております。 RS232C通信制御についてはThreadクラスを派生させたクラスを 作成し、マルチスレッド処理として、アプリ起動中に、常に動作させたい と考えています。 このとき、RS232C通信制御するスレッドを 開始するタイミング、終了するタイミングはメインアクティビティのどの タイミングで行うのが1番よいのでしょうか? 現状は以下で考えています。 public class MainActivity extends Activity { ComCtrl m_ComCtrl ; // RS232C通信制御スレッド protected void onCreate(Bundle savedInstanceState) { m_ComCtrl = new ComCtrl( null ) ; // スレッド生成 m_ComCtrl.start() ; // スレッド開始 } protected void onDestroy() { m_ComCtrl.halt() ; // スレッド終了(スレッドメインループを終了させる独自メソッド) } }

    • ベストアンサー
    • Java
  • マルチスレッドプログラミングについて

    マルチスレッドプログラミングについていくつか教えて下さい。 マルチスレッドの基礎がまだ分かってないので初心者でも分かり易いようにお願いします。 1:イベントオブジェクトについて教えて下さい。 「イベントオブジェクト」の概念がよく分かりません。 ○シグナル状態と非シグナル状態とはどういう状態なのでしょうか? ○自動リセットの場合ではどのタイミングで切り替わっているのでしょうか?(下記のソースの場合) ○手動リセットの場合ではどのタイミングで切り替えればよいのでしょうか?(下記のソースの場合) 2:CloseHandle() と ExitThread() について教えて下さい。 ○この2つの関数の役割の違いについて教えて下さい。 「スレッドハンドルを閉じる=スレッドを終了」ではないのでしょうか? また、これらの関数実行時にシグナル状態は気にする必要はありますか?(シグナル状態にしなくてよいのか?) 下記のソースは簡略化のためかなり省略されています。 DWORD WINAPI ThreadProc( DWORD i ) { while( true ) { DWORD r = WaitForMultipleObjects( 2, hEvent, FALSE, INFINITE ); if( r == WAIT_OBJECT_0 ) { // 処理1 } else if( r == WAIT_OBJECT_0 ) { // 処理2 } else { ExitThread( TRUE ); // スレッド終了 } } } void MainProc() { // 自動リセットのイベントオブジェクト作成 for( int i=0; i<2; i++ ) { hEvent[i] = CreateEvent( NULL, FALSE, FALSE, NULL ); } // スレッドを作成 hThread = CreateThread( NULL, 0, ThreadProc, NULL, 0, &dwThreadID ); }