昔、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#ではどういうふうに実現するのが一般的なのでしょうか?
上記のような例の場合、非同期で動作させたいと思うのですが...。
どなたか教えてください。
お願いします。
No.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)があなたのイメージと少し違うかも知れないが、複数のスレッドがメインスレッドに対してそれぞれ起動と終了を通知するのではなく、単純にががっとスレッドたちを起動して全部が終わるのをざざっと待って全部が終わったら自動的に親が終了を判断できるという方がシンプルになるんじゃないかな。
回答をありがとうございます。
まだC#を始めたばかりで、正直ちょっとややこしいな、という印象がありましたが、
よく読めば、ああなるほどと、大変参考になりました。
いろいろとWebで調べてみたのですが、PostMessage のようなことは BeginInvoke で、
という書き込みが散見されました。
そちらのやり方にも興味があり、Delegate の BeginInvoke も調べてみて、それ自体
はなんとなく分かったのですが、どうやれば PostMessage の代替になるのかまでは分
かりません。
また、その件でも質問してみようかと考えているところです。
もしご存知でしたら、またヒントをいただけると、大変ありがたいです。
今回は勉強になりました。
ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(学校・勉強) この中で間違ってある説明はありますか?詳しい方に教えていただきたいです。 A. 1つのプログラムが複 2 2023/07/14 01:15
- Visual Basic(VBA) 動かなくなってしまった古いVBAを動くようにしたい 8 2022/09/20 13:57
- グループウェア slackについて取り急ぎ教えて頂きたいことがあります 2 2022/04/08 09:05
- JavaScript [Java] Edgeでのアドレスバー非表示について 3 2022/04/20 17:51
- その他(コンピューター・テクノロジー) PC利用中に勝手に起動する窓を消し去る方法を教えて下さい。 1 2023/05/08 16:48
- Visual Basic(VBA) 3つのプロシージャをまとめたら実行時エラー発生で対応不能 6 2022/05/17 01:47
- PHP ここでの ②if($su_d<>"")の比較演算子 を使う理由は 1 2022/03/26 02:33
- iOS Gragebandでのみ左クリックが有効にならない 1 2022/08/19 13:18
- Visual Basic(VBA) VBA 参照先で選んだファイルをコピーし、出力先に別名で保存したい 8 2022/05/13 20:37
- PostgreSQL DBFluteについて質問です。 環境:PostgreSQL java8 前提:webアプリケーショ 1 2022/07/07 00:49
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VC++スレッドの正しい終了のさ...
-
メモリアクセスの競合について
-
アラート可能な待機状態とは
-
マルチスレッドプログラミング...
-
マルチスレッドについて
-
_beginthreadexで生成したスレ...
-
Windows上で、シグナル(SIGTERM...
-
WaitForSingleObjectの使い方に...
-
[Windowsプログラミング] スレ...
-
VC++ メインループでのイベン...
-
同一スレッドで、ロックをかけ...
-
C# スレッドから親ウィンドウへ...
-
マイクロソフトedge で5チャン...
-
待機関数(WaitForMultipleObjec...
-
.NetのBackgroundWorkerクラス...
-
C言語で一定時間待機後、再実行
-
スレッドの終了はどうやるんで...
-
Linuxでスレッド優先度って変え...
-
sleep関数とは?
-
別スレッドのデータを受信できない
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
WaitForSingleObjectの使い方に...
-
スレッドにて同一メモリの書き...
-
VC++スレッドの正しい終了のさ...
-
スレッドの監視方法について
-
Windows上で、シグナル(SIGTERM...
-
スレッドの終了の仕方
-
スレッドの安全な終了のさせ方
-
CWnd::OnTimerのスレッドの取得
-
MFC通信プログラムマルチスレッ...
-
Linuxでスレッド優先度って変え...
-
.netアプリへのSendMessageでフ...
-
VB2005 シリアル通信のClose処理
-
別スレッドからメインダイアロ...
-
マルチスレッドについて
-
スレッドの終了はどうやるんで...
-
マルチスレッドプログラミング...
-
別スレッドのデータを受信できない
-
特定のスレッドの破棄
-
msec単位のWait Timerが作れない!
-
C# スレッド終了の監視について
おすすめ情報