アプリ版:「スタンプのみでお礼する」機能のリリースについて

昔、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#ではどういうふうに実現するのが一般的なのでしょうか?

上記のような例の場合、非同期で動作させたいと思うのですが...。

どなたか教えてください。
お願いします。

A 回答 (1件)

基本的にはThreadクラスでどうとでもなるし、Formのボタンクリックによるイベントハンドラがスレッドを起動するのであればBackgroundWorkerが中間スレッドになるのが良いかも。

以下、画面の描画やマウスボタンクリックの処理をしているスレッドをUIスレッド、複数のスレッドを起動して終了を待ち、最後にUIスレッドに報告するスレッドを子スレッド、何かしらの処理をする複数のスレッドを孫スレッドとして説明する。

BackgroundWorkerクラスを使う時の流れ
・BackgroundWorkerのインスタンスを作る
・Startボタンクリックイベント→BackgroundWorker#RunWorkerAsyncを呼び出すのとStartをDisable、EndをEnableにするのをやる(*1)。
・BackgroundWorker#DoWorkイベント→今ここは子スレッドで動いている。ここで複数の孫スレッドを起動し、全ての孫スレッドの終了を待ってからDoWorkイベントを終了する。孫スレッドから子スレッドへなんらかの通知をしたい時にはdelegateなどを用いてコールバックすれば良い。
・子スレッドで動作するDoWorkが終了すると自動的にUIスレッドでBackgroundWorker#RunWorkerCompletedイベントが呼ばれる(*3)のでボタンのEnable/Disableを切り替える(*2)。
・EndボタンクリックイベントではBackgroundWorker#CancelAsyncを呼び出す。子スレッドで動いているDoWorkの中ではBackgroundWorker#CancellationPendingがtrueなら孫スレッドに停止命令を出すなどする。
・DoWorkを動かしている子スレッドから画面に何か通知したい時はBackgroundWorker#ReportProgressを呼び出し、UIスレッドではBackgroundWorker#ProgressChangedイベントに応答して画面にメッセージ出すなどする。

(*3)があなたのイメージと少し違うかも知れないが、複数のスレッドがメインスレッドに対してそれぞれ起動と終了を通知するのではなく、単純にががっとスレッドたちを起動して全部が終わるのをざざっと待って全部が終わったら自動的に親が終了を判断できるという方がシンプルになるんじゃないかな。
    • good
    • 0
この回答へのお礼

回答をありがとうございます。

まだC#を始めたばかりで、正直ちょっとややこしいな、という印象がありましたが、
よく読めば、ああなるほどと、大変参考になりました。

いろいろとWebで調べてみたのですが、PostMessage のようなことは BeginInvoke で、
という書き込みが散見されました。

そちらのやり方にも興味があり、Delegate の BeginInvoke も調べてみて、それ自体
はなんとなく分かったのですが、どうやれば PostMessage の代替になるのかまでは分
かりません。

また、その件でも質問してみようかと考えているところです。
もしご存知でしたら、またヒントをいただけると、大変ありがたいです。

今回は勉強になりました。
ありがとうございました。

お礼日時:2014/03/26 14:50

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!