VC++ 2008 を使用しています。MFCについて質問です。
MFCのダイアログベースクラスを作成し、そこにCWinThreadの派生クラス
を追加しました。このスレッドクラスの処理をイベントハンドラによって
bool型のフラグを使って中断させるようなものを作りたかったのですが、
繰り返し処理をしている最中にボタンが押せない、つまりスレッドのはずなのに
並列処理になっていないという事態になっています・・・。
メインダイアログのクラスからCWinThreadの派生クラスを呼び出すだけでは、
スレッドにならないのでしょうか?
作り方は色々なサイトでかいてあるとおり、メインダイアログ側では
CRuntimeClass *pRuntime = RUNTIME_CLASS(CMessage);
CMessage* m_Message = static_cast< CMessage* >( pRuntime->CreateObject() );
m_Message->CreateThread(); で作成しました。
スレッドクラスでは Run() 関数の中にフラグがオフに(メインダイアログ
のキャンセルボタンが押される)なるまでメッセージボックスを表示し続ける
という処理を書いています。
どうしたら並列処理がうまくいくか教えていただきたいです。お願いします
>スレッドクラスでは Run() 関数の中にフラグがオフに(メインダイアログ
>のキャンセルボタンが押される)なるまでメッセージボックスを表示し続ける
>という処理を書いています。
メッセージボックスって
メッセージボックスのokボタンを押すまで表示され続けるものじゃないの。
メッセージボックスじゃなくてモードレスウィンドウか。
>bool型のフラグを使って中断させるようなものを作りたかったのですが、
具体的にどんな処理なのか知らないので推測
セカンダリスレッドでウィンドウ出していて
そのセカンダリスレッドでループでボタン押されたかチェックしている
というなら間違え。
プライマリスレッドで長時間の処理するとウィンドウが応答なしになるから
スレッドを使ったんだと思うけど
セカンダリスレッドでウィンドウ出したら意味ないんじゃないの。
ウィンドウを表示しないワーカースレッド向きな処理したい気がする。
確かMFCのスレッドって終了すると自動でdeleteされてしまうから
スレッドが終了したか確認しようとすると不正なメモリアクセスになるから
サスペンド状態でスレッドを作成して自動でdeleteされないようにして
スレッドハンドルでスレッドが存在しているか終了しているかチェックするのに使って
いらなくなった明示的にdeleteするという面倒なんだよな。
bool型のフラグはvolatileにしてなくても大丈夫だと思う。
他の関数を呼び出さないとか
単純なものでない限り最適化されないから。
>繰り返し処理をしている最中にボタンが押せない、つまりスレッドのはずなのに
どういうこと?
* ボタンが凹んだ絵にならない
* ボタン押したときのハンドらが呼ばれない
TRACEマクロ、ブレークポイントでデバッガで追えば判ると思うけど。
一つのスレッドでは処理は一つしか出来ない。
つまり、長く掛かるような処理が走っている最中は
ウインドウメッセージの処理が出来ないので
ウインドウの制御とかユーザーのオペレーションに反応できなくなる。
だから、長い処理をウインドウメッセージの処理とは別のスレッドに
追い出してしまえば、ウインドウメッセージの方は処理ができるように
なるから、ボタンをしたときの処理とかができるようになるわけです。
ウインドウメッセージと長い処理を分けてしまう事が目的で
マルチスレッドにする事が目的になるわけなので
ウインドウを持たないワーカースレッドにするのが正解だと思います。
どうしてもCWinThreadの派生にする必要があるのであれば、
その理由まで説明すれば、他のレスがつくかもしれません。
うわ、日本が変なので訂正。
誤)
> ウインドウメッセージと長い処理を分けてしまう事が目的で
> マルチスレッドにする事が目的になるわけなので
> ウインドウを持たないワーカースレッドにするのが正解だと思います。
正)
ウインドウメッセージと長い処理を分けてしまう事が
マルチスレッドにする目的になるわけなので
ウインドウを持たないワーカースレッドにするのが正解だと思います。
スレッドについてもう少しマニュアルを読みましょう。特に
「ユーザーインターフェーススレッド」と、
「ワーカースレッド」の違いと用法についての解説部分が
役に立つと思います。
MFCのポリシーでは
1.UI Thread ではユーザーの操作待ち以外何もしない。
2.WORKER Thread では、UI&Windowは提供しない。
というもののようですよ。
皆様回答頂きありがとうございました。 目的は、ワーカースレッドの作り方は
覚えたので次はユーザーインターフェーススレッドを覚えて、メッセージというものを
勉強しなさい、と言われたのでユーザーインタフェースについて調べていました。
単純に、インターフェーススレッドで検索したらまずCWinThreadの派生クラスを
作る・・・というようなことが書いてあったのでそのとおりにしたのですが、いまいち
使い道がわからないのです・・・。
勉強する順番に違和感を感じます。
ウィンドウのプログラミングをする時点でメッセージドリブンを(一部でも)
理解する必要がありますよね。
で、メッセージドリブンでプログラミングをしていくと、PATIOさんが言って
いる通り、
> 長く掛かるような処理が走っている最中は
> ウインドウメッセージの処理が出来ない
という状況になってしまい、ウィンドウプログラムとしてまずい状況になる、
そこで、ワーカースレッドを作成して、並行処理させるわけです。
で、ワーカースレッドを作れるようになっているのだから、ウィンドウのプロ
グラミングは既にできるんですようね。だったら、メッセージの勉強って何?
という感じです。
> まずCWinThreadの派生クラスを作る
のはMFCのフレームワークに隠されているため、ユーザ側でプログラムするこ
とは一般的ではありません。VCでMFCアプリを作成するとCWinAppの派生クラス
が作成されますが、このCWinAppがCWinThreadから派生されているので、わざ
わざ自分で派生させる必要はないんです。
実際に自分でUIスレッドを作成しなければならない状況になったことはあり
ません。
# たまたまかもしれませんが。
ついで言っておくとMSDNのCWinThread::Run には
「Run 関数をオーバーライドすることはほとんどありません。しかし、特別な動作を実装
するためにオーバーライドすることもできます。」
って書いてある。
つまりメッセージの勉強をするため、自分でRun関数を書くことはないってこと。
勉強のためにその動作を追うってのは有りだと思うけど、その前に基底クラスの
動作がわかっていないとどうにもならないんじゃないかな。
使い道はないな。
プライマリスレッドがUIスレッドだからそれで十分。
UIスレッドが複数あるとデッドロックしたり
マルチスレッドなのでテスト・デバッグが大変とかデメリットだな。
メッセージを勉強したいなら、ここでSDKを勉強するというのはどうですか?
http://www.kumei.ne.jp/c_lang/index_sdk.html
ぜひ、本を買うのをすすめます。
すべてSDKでプログラムするためには、メッセージの知識も必要だからいい勉強になる
と思う。
MFCを利用するにしても、一度はSDKで組んでみるのもいいと思います。
ユーザー定義の「UIスレッド」はあまり使わないと思うので、知ったところで
あまり有益にはならないと思います。
(会社)
それよりは、「CWinApp, CFrameWnd, CView, CDocument」がどういうものなのかを理
解するのが大事だと思う。
この4つが理解できれば,「UIスレッド」も自然に理解できると思います。
追加、修正
(会社)→ (会社でUIスレッドの使用をすすめているのなら別です。)
みなさん ありがとうございました。MFCを使わないアプリケーション
を作って勉強してみたいと思います。