MFCマルチスレッドについて

このQ&Aのポイント
  • COMやIOボードからの入力に応じて動作するアプリを作成しています。AfxBeginThreadにてワーカスレッドを作成し、制御関数内でメンバ関数を実行しています。
  • AfxBeginThreadにて*thisを送り、制御関数内で親スレッドのクラスのメンバ関数を実行しています。
  • 表示部分の処理はクリティカルセクションにしていますが、実際の動作についてわかりません。
回答を見る
  • ベストアンサー

MFCマルチスレッドについて

MFCマルチスレッドについて COMやIOボードからの入力に応じて動作するアプリを作っています。 AfxBeginThreadにてそれぞれワーカスレッドを作成しCOMやIOから入力があれば AfxBeginThreadを呼んでいるクラスにあるメンバ関数を実行しようとしています。 AfxBeginThreadにて*thisを送り、制御関数内で、mycls->OnButton***()というような 感じで現在は作っています。(OnButton***になっているのはデバッグ用にボタンで あらかじめ作成している関数のためです。) このときに、mycls->OnButton***()は親スレッドで動いていると考えていいのですか? あくまで親スレッドのクラスのメンバ関数を制御関数が動いている子スレッドで実行 しているだけなのでしょうか? 実は、ログ表示のため制御関数の中(受信データを表示)と、mycls->OnButton***()の中 (作業結果を表示)に同じエディットコントロールへの表示部分があります。 表示部分の処理は、いったんCStringで読み込んできて最大文字数チェックを行い、 再度文字数を調節して書き直しということをやっているため、一応クリティカル セクションにはしているのですが、実際どう動いているか分からないため、やり忘れ ていることや、やってはいけないことをやってそうです。 すいませんがご教授願います。

質問者が選んだベストアンサー

  • ベストアンサー
  • reset_cat
  • ベストアンサー率68% (94/138)
回答No.2

>AfxBeginThreadにて*thisを送り、制御関数内で、mycls->OnButton***()というような 感じで現在は作っています。 この方法なら、 「親スレッドのクラスのメンバ関数を制御関数が動いている子スレッドで実行しているだけ」 になります。 ここで問題になりそうなのは、 1.同じ関数を別々のスレッドが実行することになるので、同期処理が必要になるかもしれない。 2.親スレッドがウィンドウプロシ-ジャを実行している場合、子スレッドからは親スレッド所有のウィンドウ操作を行うことはできない。 1に関してはクリティカルセクションで保護しているようなのでよさそうですが、2に関しては、親スレッドがウィンドウを所有している上に再度表示をしなおすということなので、問題になるかもしれません。 表示に関わるコードがある場合は、その部分をメッセージハンドラとして実装し、子スレッドから#1さんが挙げているSendMessage、PostMessageなどを利用して親スレッドに実行させる方がよいかと思います。

nori1112
質問者

補足

皆さんありがとうございます。 ネットで探してみると、 http://www.wit-systems.co.jp/MultiTh01.htm のようなページもありやはりメッセージで処理したほうが良さそうでしたので 組み替えて今のところ何も起こらず動いています。 ありがとうございました。

その他の回答 (1)

  • koi1234
  • ベストアンサー率53% (1866/3459)
回答No.1

SendMessageやPostMessageなどでボタンクリックイベントなどを飛ばしているなら 処理されるのはメインのスレッドになりますが 質問のように直にメンバー関数読んでいるのであれば 実行はそのスレッド内で行われるはずです

関連するQ&A

  • マルチスレッドについて

    現在”猫でもできる”の87、88章を学んでおります。 まず87章でマルチスレッドの根本的なやり方を学びましたが、いきなり疑問が浮かびました。 _beginthread関数によりスレッドをスタートさせ、この関数で登録した関数内で_endthread関数を実行し終了させていることは分かります。 しかし_beginthread関数で登録した関数に引数を渡す処理がどの部分で行われているのかわかりません。 登録する関数はvoid型で引数はvoid*型でなければいけないことは分かったのですが、プログラムのどこを見てもこの登録した関数に引数を渡す処理が行われていません。 その辺の動作の説明を分かる方でいいのでよろしくお願いします。 そして88章では排他制御のマルチスレッドを行うプログラムの製作を行っているのですが、ちょっとした疑問が浮かびました。 EnterCriticalSection関数、LeaveCriticalSection関数ではさまれたプログラムは排他制御され他からアクセスされない。 この関数はこんな理解で良いんですかね? この理解で行くと、88章で説明していきますが、子ウィンドウを2つ作成しそれぞれのプロシージャ内で排他制御された関数をスレッドとしてスタートしています。 この2つのスレッドの動作についてですが、互いに排他制御関数が記述されているため、動作としてはまず左の子ウィンドウのスレッドが処理されている場合、右の子ウィンドウのスレッドは停止している。そして左の子ウィンドウのスレッドの排他制御が解放されたときに、右の子ウィンドウのスレッドが開始する。 そしてあるとき左の子ウィンドウのクライアントウィンドウ内で右クリックされた場合、その時点で排他制御されたスレッドが終了するのを待ち、終了したらcountを+1する。 こんな動作が行なわれていると理解してよいのでしょうか?

  • マルチスレッドについて。

    今、大きな配列を元に処理を行うプログラムを作成しています。 シングルスレッドでも十分速度を向上するようチューニングに成功しましたが、マルチスレッド化をすればさらに速度を向上させることができるだろうと考え、先日マルチスレッドかに成功しました。 しかし・・・奇妙な現象が起こりました。 マルチスレッドで性能を引き出すには、排他制御はないほうが良いと考え、メモリは食いますがスレッドに与える入力情報(大きな配列)を2つ用意し、排他制御なしの2スレッドを実行できるようにしました。しかしやはりメモリを消費しすぎてしまうため、配列にアクセスする部分のみ排他制御を行うようクリティカルセクションを設定し入力情報を2スレッドで共有して処理を行うよう組み替えました。 結果、やはり排他制御なしの場合よりはるかにスピードダウンしてしまい、シングルスレッドより少し早い処理時間で終了してしまいました。 余りにも悔しいため、ちょっと危険な実験だとは思いましたが、入力情報を2つのスレッドで共有しているにもかかわらず、排他制御の部分、つまりクリティカルセクションを取り除いて実行してみようと考えました。予想としては同時にアクセスし衝突が起きてエラーで停止してしまうと考えましたが・・・・・・ 結果なぜかエラーなく処理をし続け、普通に終了してしまいました。 これはなぜでしょう? 偶然にも共有情報に同時にアクセスすることがなかったためでしょうか?

  • メインスレッドのPostMessageとマルチスレッドでの処理

    お世話になります、fujicafeと申します。 現在Visual Studio 2005にてVC++のプログラムの作成をしており、 お聞きしたいことがありまして、こちらにて投稿させていただきました。 質問したい内容はPostMessageによる非同期呼び出しによるメインスレッド関数の処理と、別スレッドからのメインスレッド関数呼び出しによる処理の違いについてです。 現在、メインスレッドにマルチメディアタイマーを使って、ある時間間隔毎にメインスレッドの関数を呼び出しています。その関数の呼び出しにはPostMessageを使用しています。 その関数の呼び出しをAfxBeginThreadを使用して、メインスレッドから別スレッドを作成し、その別スレッド内にてメインスレッドのオブジェクトを作成して、実行したいメインスレッドの関数を呼び出すと、もともとのPostMessageを使用して関数を呼び出すのとでは処理としてどのような違いがあるのでしょうか? スレッドを別にするということで、メインスレッド側に負荷をかけないといったことが違うのでしょうか? だいぶ検討はずれの質問かとは思いますが、ご教授よろしくお願いいたします。

  • マルチスレッドのスレッド数を増やしたい

    <プログラム環境> Windows XP VC++6.0 MFC AppWizard(exe) ダイアログベース <質問概略> CWinThread*を使って無限ループのスレッドを作ったのですが、 無限ループのスレッドをもう一つ作り、同時に実行しようとするとアクセスバイオレーションのエラーでます。 複数スレッドの作り方を教えていただけますと幸いです。 <質問詳細> 現状の正常に実行できるソースの必要最小限を書きます。 <.h> class CMyDlg : public CDialog{ public:   static UINT ThreadFunc( LPVOID pParam );   void Thread(); // スレッドの処理 protected:   CWinThread* m_pThread;//スレッドのアドレス }; <.cpp> void CMyDlg::OnButton(){   m_pThread = AfxBeginThread( ThreadFunc, this );   for(;;) /*無限ループ処理1*/ ; } UINT CMyDlg::ThreadFunc( LPVOID pParam ){   ((CMyDlg*)pParam)->Thread();   return 0; } void CMyDlg::Thread(){   for(;;) /*無限ループ処理2*/ ; } これに、 void CMyDlg::Thread2(){   for(;;) /*無限ループ処理3*/ ; } のようなスレッドを追加したいのですが全然出来ません。 宜しければご指摘お願い致します。

  • MFCのCStringについて

    MFCで、CStringをメンバとして含むクラスと、このクラスのオブジェクトを動的に生成して値を代入し、生成したオブジェクトへのポインタを返す関数を以下のように定義しました。 class Record { public:  long Id;  CString Str; }; Record* CreateRecord(long Id_in, CString Str_in) {  Record* ret;  if ((ret = (Record*)malloc(sizeof(Record))) == NULL) {   return NULL;  }  ret->Id = Id_in; // (1)  ret->Str = Str_in; // (2)  return ret; } この関数のコンパイルはうまくいきますが、関数実行時にメモリ参照エラーとなります。 調べてみると、(1)のlong型変数への代入はうまくいっているのですが、(2)のCString型変数への代入がうまくいっていないようです。 既にインスタンス化されているRecord型オブジェクトへのポインタを受け取り、それに代入するという関数であればうまく動きました。 (例) void SetRecord(Record* received, long Id_in, CString Str_in) {  received->Id = Id_in;  received->Str = Str_in; } 先に示したCreateRecord関数は、どこが良くないのでしょうか。

  • AfxBeginThread の引数について

    こんにちは。 MFCを使用した新規スレッド作成を行うために、API「AfxBeginThread」を使用しようと考えています。 そこで、質問なのですが、新規作成したスレッドに引数を渡したい場合、AfxBeginThreadの第3引数に設定するようなのですが、複数の引数を渡したい場合には、具体的にどのような手順を踏めばよいのでしょうか。 MSDNによると、第3引数の説明は、「pfnThreadProc の関数宣言の引数に見られるような、制御関数に渡す引数。」とありますが、いまいち分かりません。 よろしくお願いします。

  • VC++スレッドの正しい終了のさせかた

    VC++6.0にてAfxBeginThreadで m_bAutoDelete = TRUEにてスレッドをおこしております。 この終了時に制御関数のwhileループを脱する様にし、 正常にスレッドを終了させているつもりです。 この後、再度(アプリは継続して起動したまま) AfxBeginThreadにて全く同じ処理で再開すると、 なぜか、前のスレッドが未だ動作しているかのごとく 制御関数内のTRACEが2重に出力されます。 再度、停止し、またスレッド起動すると、 今度は3重になったかの様な動作をします。 スレッドが正しく終了されていないのでは?と思った現象として、 1回起動時にアプリを終了させると正常終了しますが、 2回起動以上は必ずスレッドのメモリーリークが出ます。 メモリーリーク個所はAfxBeginThreadでした。 制御関数内で必要ないとは思いましたが、終了時に AfxEndThreadを使用しましたが現象は同じでした。 そこで質問です。 1)この現象は、スレッドが正常に終了されていない事に起因しているのでしょうか? 2)スレッドを正しく終了させるにはどうすればいいのでしょうか? 当方、制御関数がループを抜け、さらにm_bAutoDelete = TRUEであれば オブジェクトも自動的に破棄されると思っていたのですが。。。 以上、よろしくお願いします。

  • ダイアログを終了させてもハンドルが1つ増加したまま。。。

    VC++のMFCを使ってダイアログベースのEXEを造っています。 ハンドルのリークが発生し、困っています。 <動作内容> メインのダイアログで、ボタン押下により別のダイアログを表示します。 DoModal()でモーダルダイアログを作成します。 別のプロセスからブロードキャストされるメッセージを処理したいため、 ボタン押下のルーチンで DoModal() せずに、スレッドを作成し、 そのスレッドで DoModal() を実行しています。 スレッド作成は AfxBeginThread() を使用しています。 <サンプルソース> ●メインダイアログ // ボタン押下のルーチン void CTestModalDlg::OnButton1() { AfxBeginThread( TestDlgThread, (LPVOID)this, THREAD_PRIORITY_NORMAL ); } // スレッド static UINT TestDlgThread(LPVOID pThis) { CTestDlg1 Dlg; Dlg.DoModal(); } ●DoModal() で表示されるダイアログ 何も手を加えてない、デフォルトのまま。 <結果> DoModal() で表示されたダイアログを CDialog::OnCancel() で終了させ、 メインのスレッドが終了しても、ハンドルカウントが1つ増加しています。 Sleep() を入れて値をみてみると、 ・スレッド作成:2増加 ・DoModal() でダイアログ表示:1増加 ・OnCancel() で終了:増減なし ・スレッド終了:2減少 =>結果、1増加となっていました。 以下のパターンでは問題ありませんでした。 ・スレッドを作成+終了(ダイアログ表示しない) ・スレッドを作成せずに、ボタン押下ルーチンから DoModal() でダイアログ表示+終了 ということで、AfxBeginThread()、DoModal() 自体は問題ないのですが、 スレッドを作成して DoModal() するとリークが発生します。 識者の方、原因、対策など、ご教授願います。

  • クラスの扱いについて

    VCで簡単なプログラムを造っています。 ダイアログベースです。 エディットボックスへのアクセス方法がわかりません。 識者の方、ご教授願います。 簡単にソースを載せます。 以下は、ボタンを押した時に動作するルーチンです。 void CTestDialog::OnButton1() { CreateThread(, , Sub, , ,); } Sub() が作成されたスレッドで動作する関数です。 void Sub() { CString csText; csText.Format("てすと"); SetDlgItemText(IDC_EDIT1, csText); } IDC_EDIT1 が CTestDialogクラスのエディットボックスです。 Sub() の中でこのエディットボックスに書きたい。 Sub() を CTestDialogクラスとして定義するのか、または SetDlgItemText関数で IDC_EDIT1 が CTestDialogクラスであると 指定するのか、などわかりません。 どこに、どういう記述をすればいいか教えてください。

  • Delphiのマルチスレッドの割り込み処理について

    Delphiのマルチスレッドの割り込み処理について教えて欲しいのですが、ファイルをスレッドオブジェクトで作成して クラス名.Execute関数内でSynchronizeメソッドを使用しています。 本にはSynchronizeメソッドは「渡したメソッドが実行され終了するまで待ちます」と書いてあり、テストプログラムを作成してもそうでした。ということはSynchronizeメソッドは普通の関数と一緒のような気がしてしまうのですが、違うのでしょうか? Procedure MyThread.Execute begin Synchronize(AAA); AAAの処理が終了するまで待機している end; Procedure TmyThread.AAA; begin 'したい処理' end;

専門家に質問してみよう