C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[2]: マルチスレッド、await


(過去ログ 178 を表示中)

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■102148 / inTopicNo.1)  マルチスレッド、await
  
□投稿者/ y sakuda (1回)-(2023/07/11(Tue) 17:51:57)

分類:[C#] 

環境はWindows11、VisualStudio2022です。
C#は初心者です。
長時間かかるプログラムで、中断してSaveできないと話にならないということで、マルチスレッド化したのですが、
サブスレッドからUIを変更すると、当然エラーになります。最終的には、サブスレッドから、delegate/Invokeで
メインスレッドからUI操作すれば良いことが分かり、やりたいことはすべてできました。(100%理解してませんが)

ただ、その過程で試したものが、上手く動いていると言えば言えるのですが、正しくないような気もしてもやもやが残りましたので、
質問させていただきます。
  public partial class Form1 : Form
    {
        Boolean wStopF;
        public Form1()
        {
            InitializeComponent();
        }

        private async void btnStart_Click(object sender, EventArgs e)
        {
            wStopF = false;
            MessageBox.Show("Main "+Thread.CurrentThread.ManagedThreadId);
            await SubProc();
            MessageBox.Show("Completed");
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            wStopF = true;
        }
        private async Task SubProc()
        {
            MessageBox.Show("Sub " + Thread.CurrentThread.ManagedThreadId);
            int wN = 0;
            while (true)
            {
                if (wStopF) break;
                int wDummy = 0;
                for (int I = 0; I < 100000000; I++)
                {
                    wDummy++;
                }
                wN++;
                label1.Text = "SubProc" + wN;              
                Application.DoEvents();
            }
            MessageBox.Show("Stop");
        }
    }

どこから、await SubProc();なんて引っ張り出したのか、今となっては良くわからないのですが、多分
https://qiita.com/toRisouP/items/a2c1bb1b0c4f73366bc6
辺りかと思います。
これだと、UIはちゃんと変更されますし、Stopボタンも機能します。ただし、DoEventsがないとStopボタンは押せない状態になります。
質問は、
1.このプログラムだとすべてメインスレッドで動いているのに、なぜStopボタンが押せるのか?
2.このプログラムの状態は、Stopボタンは生きているが、疑似的なマルチスレッドで、実質的にシングルスレッドで動いている
  と言う理解で良いのか?
よろしくお願い申し上げます。

引用返信 編集キー/
■102149 / inTopicNo.2)  Re[1]: マルチスレッド、await
□投稿者/ Hongliang (1289回)-(2023/07/11(Tue) 18:12:41)
> 1.このプログラムだとすべてメインスレッドで動いているのに、なぜStopボタンが押せるのか?
Application.DoEvents()によって、
「キーボードやマウスの入力があったらそれを処理する」
「画面更新要求があったら画面を書き換える」(label1.Textがこれですね)
といった一通りの処理がその場で実行されるからです。
ユーザの入力や画面更新要求などはメッセージキューというキューに一旦置かれ、メインスレッドの手が空いた時にキューから取り出されてそれぞれ処理されるのですが、それを強制的に処理させるのがDoEventsになります。

> 2.このプログラムの状態は、Stopボタンは生きているが、疑似的なマルチスレッドで、実質的にシングルスレッドで動いている
>   と言う理解で良いのか?
実質的にというか、事実としてシングルスレッドで動いていますね。
(.NETのフレームワーク自体がいくつか暗黙にスレッドを作るので、アプリケーション全体としては複数スレッドが存在してはいますが)
引用返信 編集キー/
■102150 / inTopicNo.3)  Re[2]: マルチスレッド、await
□投稿者/ y sakuda (2回)-(2023/07/11(Tue) 18:33:18)
No102149 (Hongliang さん) に返信

早々にご回答ありがとうございます。

> ユーザの入力や画面更新要求などはメッセージキューというキューに一旦置かれ、メインスレッドの手が空いた時にキューから取り出されてそれぞれ処理されるのですが、それを強制的に処理させるのがDoEventsになります。
>
なるほど。分かりました。


> 実質的にというか、事実としてシングルスレッドで動いていますね。
> (.NETのフレームワーク自体がいくつか暗黙にスレッドを作るので、アプリケーション全体としては複数スレッドが存在してはいますが)
やはり、そういうことなんですね。
もやもやがすっきりしました。

引用返信 編集キー/
■102151 / inTopicNo.4)  Re[3]: マルチスレッド、await
□投稿者/ y sakuda (3回)-(2023/07/11(Tue) 18:33:53)
No102150 (y sakuda さん) に返信
> ■No102149 (Hongliang さん) に返信
>
> 早々にご回答ありがとうございます。
>
>>ユーザの入力や画面更新要求などはメッセージキューというキューに一旦置かれ、メインスレッドの手が空いた時にキューから取り出されてそれぞれ処理されるのですが、それを強制的に処理させるのがDoEventsになります。
>>
> なるほど。分かりました。
>
>
>>実質的にというか、事実としてシングルスレッドで動いていますね。
>>(.NETのフレームワーク自体がいくつか暗黙にスレッドを作るので、アプリケーション全体としては複数スレッドが存在してはいますが)
> やはり、そういうことなんですね。
> もやもやがすっきりしました。
>
解決済み
引用返信 編集キー/
■102152 / inTopicNo.5)  Re[1]: マルチスレッド、await
□投稿者/ WebSurfer (2736回)-(2023/07/11(Tue) 18:37:39)
No102148 (y sakuda さん) に返信

.NET Framework 4.5 以降で利用できる async / await を使って非同期で実行
されるタスクをキャンセルするには CancellationTokenSource クラスを利用
します。

一般的なパターンは以下の通りです。

(1) CancellationTokenSource クラスのインスタンスを作成する。

(2) CancellationTokenSource.Token プロパティで CancellationToken を
  取得し、キャンセルをリッスンするタスクに渡す。

(3) タスクにはキャンセル通知を適切に処置するコードを実装しておく。

(4) CancellationTokenSource.Cancel メソッドを呼び出し、リッスンして
  いるタスクにキャンセルを通知する。

(5) キャンセル通知を受けたタスクは、あらかじめ実装されているコードに
  従ってキャンセル処置を行う。

詳しくは以下の Microsoft のドキュメントを見てください。

マネージド スレッドのキャンセル
https://learn.microsoft.com/ja-jp/dotnet/standard/threading/cancellation-in-managed-threads

実装例は以下の記事に書きましたので興味があれば読んでください。

非同期タスクのキャンセル
http://surferonwww.info/BlogEngine/post/2020/09/27/cancellation-of-async-task.aspx

引用返信 編集キー/
■102154 / inTopicNo.6)  Re[2]: マルチスレッド、await
□投稿者/ y sakuda (4回)-(2023/07/11(Tue) 21:24:34)
No102152 (WebSurfer さん) に返信
> ■No102148 (y sakuda さん) に返信
>
> .NET Framework 4.5 以降で利用できる async / await を使って非同期で実行
> されるタスクをキャンセルするには CancellationTokenSource クラスを利用
> します。
>
情報提供ありがとう存じます。
私がやってたのは、ヘプタモンドってテンヨーのプラパズルのプログラムで、ペントミノなんかと違って、正解がどんだけあるか分からんって代物で、30時間くらい動かして、20万くらい答えがでたけど、まだ表面をひっかいた程度の感じ。
で、途中で止めて、せっかく出て結果をちゃんとSaveできるようにしたいって程度の話でした。
複数スレッドで同時並行に処理して高速化なんて分不相応なことは考えてませんから、止めるにしてもサンプルに出したようなフラッグ程度で困ってません。
プログラム自体は50年前の大型機の時代からですが、VB,C#については、1〜2年前VisualStudioが個人ユーズなら無料で使えることに気が付いて、暇つぶしにちょこちょこいじってる程度です。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -