• ベストアンサー

MFCのワーカースレッドとUIスレッドの使い分け

MFCのスレッドプログラミングに関して質問があります。 MFCにはワーカースレッドとUI(ユーザーインターフェース)スレッドの 2種類のスレッドがあるようですが、何が違って、どのように使い分けするのでしょうか? ワーカースレッドは、このうような処理に、 UIスレッドは、このような処理に、 と言う感じで教えて頂けると助かります。 どいぞ宜しくお願い致します。

  • ken2r
  • お礼率88% (82/93)

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

  • ベストアンサー
  • Dodonpa22
  • ベストアンサー率100% (4/4)
回答No.2

ワーカースレッド(以下WS)でもユーザーインターフェイススレッド(以下UI)でも スレッドはスレッドでMSが便宜上分けているだけということは覚えておいたほうが いいです。 で、本題ですが、両者の最大の違いはメッセージポンプがあるかないかです。 メッセージポンプなしがWSで、ありがUIです。ですから、作成したスレッド内で Windowsメッセージを処理しなければならないような場合、例えばセカンダリスレッドで ウィンドウを作成して、時刻を表示するとか、ユーザの入力を受け付けて何らかの 処理を施すとかはUIを使います。 そうではなく、アプリがある種のサーバで、クライアントからの要求に対してデータを返却 するだけの処理のような場合はWSで行います。(まあ、クライアントからの要求に対して いちいちWSを作るか、WaitForSingleObjectなどの待機関数で無限ループにするかなど実装 はいろいろありますが) 荒っぽい書き方をすると、Windowsのようなオブジェクト指向はUIで、旧来の コンソールアプリのような手続き型はWSだともいえます。 最初にWSとUIは便宜上分けただけといいましたが、それはどちらもスレッドの制御関数は 同じで、スレッド作成時(AfxBeginThread)の引数で条件分岐しているだけなのがその理由です。 ですから、スレッドの制御関数を調べてみるとその違いがよくわかるので、以下のソースコードを よくみてみてください。 thrdcore.cpp内のUINT APIENTRY _AfxThreadEntry(void* pParam)が制御関数で、どちらのスレッドを 使うにしてもこの関数がスレッドの制御関数として実行されるので中身をよく吟味してください。

ken2r
質問者

お礼

マルチスレッド初心者として メッセージポンプの有無の説明が納得できました。 貴重な情報を有難うございました。

その他の回答 (1)

  • unacyo
  • ベストアンサー率51% (35/68)
回答No.1

すいません、例を書いていたら長くなりました…。あくまで私はこう使っている、という内容ですが… UIスレッドは、ウィンドウ制御(初期化、描画、ボタンやタイマー等のイベント)を処理するスレッド、 ワーカースレッドはウィンドウ制御と関係無く処理をさせるスレッド、と認識しています。 簡単に言うと、長時間処理をしなければならない場合や、イベントを途中で拾わないと処理できないものはワーカースレッドを生成し、通常はUIスレッドで処理をさせると考えると良いかもしれません。 (本当にいいかは判りませんが・・・) どんな時に使うかは、こんな感じです。 私は良くダイアログウィンドウでアプリを作るのですが、長時間処理がかかるものも実装することがあります。 この長くかかる処理を、たとえばマウスの左ボタン押下(OnLButtonDown)に実装したとします。すると、ボタンを押した後、処理が終了するまで画面の再描画が行われず、ウィンドウの移動を操作してもウィンドウは動きません。(処理している最中に他アプリのウィンドウが自分のアプリより前に来て、また自分のアプリをクリックされると、再描画が行われる・・・はずですが、再描画できない、という感じです。たまにこんなアプリ見かけませんか?) これは、UIスレッドが通知されたイベントを拾ってマウス左押下処理を呼び出して、その処理から戻ってこないためで、再描画イベント(WM_PAINTメッセージ)や移動イベント(WM_MOVE)が処理できず、処理待ちとして溜まっている(待たされている)からです。 短い処理であれば、大して問題にはならないのですが、1分2分、1時間と続くと、さすがにアプリの使用者はバグった!と思うかもしれません。 また、最悪はWindowsが無応答としてタイトルバーに(無応答)をつけてしまいます。 こんな風に、処理が長くなるケースの場合、左ボタン押下処理にはワーカースレッドの生成処理を記述してワーカースレッドを起動し、ワーカースレッドでやらせいたい処理を行わせます。すると、UIスレッドは次のイベントを処理できる様になりますので、再描画もできますし、ウィンドウの移動もできます。 ただし、他のボタンを押したりすることもできるので、その辺りは、フラグで処理できない様にするか、ボタン等のコントロールをDisableにして、クリックできない様にしたりします。 結構前ですが、ユーザーがソフトに指示を与えてどの位待てるか、という調査があったのですが、大体2~3秒ということでした。(現在もこうなのかわかりません) これをすぎると、ユーザーは何かしらの操作を行ったり、異常だと思うんだそうです。 私は、ワーカースレッドにする1つの判断材料として、処理時間が2~3秒かかるか否かで判断しています。 他の要因でワーカースレッドに出来なかったりすることもありますが、この時間を越えるならば、大抵はワーカースレッドで処理させています。 処理が長くなるなら、進捗をプログレスバー等で示すことも必要となります。 (動いているかどうかユーザーに教えると言うことですね) そんな時も、ワーカースレッドにしておくと、プログレスバーの描画等も問題無く動きます。

ken2r
質問者

お礼

実際の実装例や具体的な時間など 丁寧に教えていただき有難うございました。 また、これからマルチスレッドプログラミングを始める物として 本当に良い勉強になりました。 貴重な情報有難うございました。

関連するQ&A

  • 「UIスレッド」「マルチスレッド」の違い

    Androidで、「UIスレッド」「マルチスレッド」の違い、を教えてください。 ■下記理解で合ってるでしょうか? Androidは、「シングルスレッド」の「UIスレッド」モデルなので、それを「マルチスレッド」で動かそうとすると、「ワーカースレッド」で処理する必要がある ・「マルチスレッド」=「マルチタスク」? ・「UIスレッド」とは、メインスレッドが「GUI (グラフィカルユーザーインターフェイス) 処理」を行うものを指す? ・つまり、「Android」=「UIスレッド」? ・「UIスレッド」って何の用語? Androidに特化した用語? それともJAVAの用語? あるいはそれ以外?

    • ベストアンサー
    • Java
  • スレッドの作成と起動

    <プログラム環境> Windows XP VC++6.0 MFC AppWizard(exe) ダイアログベース <質問> ボタンを押すとOnButton()に入ります。 OnButton()内でワーカースレッドを起動させたいのですが、 どのようにコーディングするのでしょうか? スレッドの作成方法も分かりません・・。 宜しければご指摘お願い致します。

  • スレッドの監視方法

    MFCを使ってマルチスレッドプログラミングを行う予定です。 そこで質問なのですが、皆さんがマルチスレッドのプログラミングを行う際 どのようにしてスレッドの状態を監視していますか? VisualStudio中にスレッドの状態を監視する方法があるのでしょうか? また、スレッドの状態を監視する定番ツールのようなものはあるのでしょうか? 定番ではなくても便利なツールがあったら有料でも構いませんので教えて下さい。 マルチスレッドプログラミングは少ししか経験がありません。 お勧めの書籍などあったら教えて頂けると助かります。 どうぞ宜しくお願い致します。 環境:WindowsXP + VS6のMFC(後にVS2100使用予定)

  • ソケットプログラミングとスレッドについて

    TCP/IPソケットを用いた通信プログラムを作成しています。その上でacceptする処理を専用スレッドにしており、accept後の受信処理をまた別のスレッドで処理しています。コンソールプログラムにおいてサーバとクライアントを用意しテストをしてみるとうまくいくのですが、MFCプログラムにおいて同じネットワーク処理を行ってみると、サーバ側へのconnectは成功するのですが、クライアント側からsendしたときにサーバ側でrecvの戻り値が必ず0にしかならず切断された状態になってしまいます。これはどういったときに発生すると考えられるでしょうか?ちなみにMFCが絡んでいるかどうかということは特にわかっておりません。 どなたかこのような経験をお持ちであればご教授お願い致します。

  • C# スレッドでフォームを扱う

    スレッドとフォームの連携について質問があります。 「開始」ボタンをクリックしたら、 「開始」ボタンのEnableをfalseにして 他のクラスのスレッドで処理を開始します (中断ボタンが押されたら処理をやめるためにスレッド採用) この時、処理が終わったら「開始」ボタンのEnableをtrueに戻したいのです。 デリゲートのコールメソッドを使ったところ、フォームを生成したスレッド以外からフォームををいじってはいけないというエラーがでてしまいました。 [a]ユーザー操作を待ち受けるフォームのスレッド [b]処理系のスレッド このようなスレッドの構成の時、[a]が[b]の処理が終わったことを知り、buttonのプロパティを変更するためには、どうすればよいでしょうか?

  • スレッド

    スレッドを生成し、データのやり取りを行うプログラムを作成しようとしているのですが、使用関数が分かりません。 どなたか、ご存知でしたら、お教えください。 スレッドの作成関数はpthread_createを使うことは分かりました。 そこからデータを送る、受けるのやり方がわかりません。 プログラムの流れ スレッドを生成し、スレッドにデータを送る。 そのスレッド内で、データを調べ期待値だったらACK、 それ以外だったら、errorを返すといった感じです。 まだスレッドに関して知識が薄い為、質問も分かりづらいと思いますが、宜しくお願い致します。

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

    <プログラム環境> 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とC++/CLIとの比較

    MFCを使ってプログラミングを今までやっていましたが、C++/CLIへ移行しようと思っています。 ただ、MFCとC++/CLIではプログラミングの自由度に差はあるでしょうか? ここでの自由度とは、思い通りの処理・機能を実現し易いかことです。 処理・機能に関しては具体的にはまだ決まってないので、一般的な話で構いません。 あと、主観で構わないのでMFCとC++/CLIとどちらが好みかも教えてもらえると幸いです。理由も聞かせてもらえるとベストです。 よろしくお願い致します。

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

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

  • C# スレッドから親ウィンドウへの通知の方法は?

    昔、MFC C++を少しかじったことがあります。 今、システム部門のお手伝いに駆り出され、 C#を勉強しながら久しぶりにプログラミングをしています。 スレッドから、そのスレッドの呼び出し元である親ウィンドウに対し、 状態の変化を通知するような場合、 C#ではどのように実現するのがふつうなのか教えてください。 例として、以下のような簡単な処理を考えます。 あるダイアログウィンドウに、2つのボタン[Start][End]があるとします。 初期状態では、[Start]が有効、[End]が無効です。 [Start]を押すと、複数のスレッドを起動し何かしらの処理を開始します。(*1) [End]を押すと、それらのスレッドに方法はともかく終了指示を送ります。(*2) (*1)ですべてのスレッドが起動すると[End]を有効/[Start]を無効とし、 逆に(*2)ですべてのスレッドが終了すると[Start]を有効/[End]を無効とします。 これらの処理を行うため、各スレッドは、呼び出し元親ダイアログウィンドウに対し、 起動直後には起動した旨を、終了直前には終了する旨の通知をします。(*3) ダイアログウィンドウでは、各スレッドからのこれらの通知を受け取り、 すべてのスレッドから通知が届き終わった際に、 [Start]や[End]のEnabledを操作して有効化/無効化します。 このとき、(*3)では、MFC C++では、WinPostMessage というものを使い、 ウィンドウメッセージ(WM_***)を送って通知する方法を利用していました。 C#でもPostMessageは使えるようなのですが、あまり使いやすくないようです。 これは、そもそもあまり使うものではないためだと思います。 現在はイベントを使っています。 PostMessageのようなものの場合はキューを介しますから、 postする側とメッセージを受け取る側は非同期になりますが、 イベントの場合は一連の処理を終えてイベントの呼び出し元に戻るまで復帰しませんよね? そこで質問なのですが、このような処理の場合、 つまり、スレッドから親ウィンドウへの通知は、 C#ではどういうふうに実現するのが一般的なのでしょうか? 上記のような例の場合、非同期で動作させたいと思うのですが...。 どなたか教えてください。 お願いします。

専門家に質問してみよう