DOBON.NETプログラミング道掲示板

[ 最新記事及び返信フォームをトピックトップへ ]

■34990 / inTopicNo.1)  Taskの入れ子の待ち方
  
□投稿者/ Wan 付き人(51回)-(2022/01/06(Thu) 10:34:44)
  • アイコン環境/言語:[VisualBasic2019 Windows10 Basic Framework4.7.2] 
    分類:[.NET] 

    下記のコードは、ボタン5を押すと子タスクと孫タスクが起動して、子タスクが、孫Taskのj>7のFalseを待って、終了する積りで書いたものです。
    Dim tokenSource As New CancellationTokenSource
    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    tokenSource.Cancel()
    End Sub
    Private Async Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
    tokenSource = New CancellationTokenSource
        Dim token As CancellationToken = tokenSource.Token
        Debug.Print($"StartTask ID:{CurrentId} スレッド:{CurrentThread.ManagedThreadId}")
        Try
          Await Task.Run(
              Async Sub()
                  Dim i As Integer = 0
                    Debug.Print($"子Task ID:{CurrentId} スレッド:{CurrentThread.ManagedThreadId}")
                    Dim 孫Task As Task = Task.Run(
                      Sub()
                          Dim j As Integer = 0
                            Debug.Print($"孫子Task ID:{CurrentId} スレッド:{CurrentThread.ManagedThreadId}")
                            While j < 7
                              If token.IsCancellationRequested Then
                                  Debug.Print("孫Taskは、停止しました。")
                                  Exit While
                                End If
                                Thread.Sleep(500) '0.5秒待つ
                                Debug.Print($"孫TaskCount:{j}")
                                j += 1
                            End While
                        End Sub)
                    While i < 5
                      If token.IsCancellationRequested Then
                          Debug.Print("子Taskは、停止しました。")
                            Exit While
                        End If
                        Thread.Sleep(500) '0.5秒待つ
                        Debug.Print($"子TaskCount:{i}")
                        i += 1
                    End While
                    Await 孫Task
                End Sub)
        Finally
          tokenSource.Dispose()
        End Try
        Debug.Print($"FinishTask ID:{CurrentId} スレッド:{CurrentThread.ManagedThreadId}")
    End Sub
    ところが、動かしてみると、どうも子タスクは、孫タスクの終了を待ってくれないようです。Awaitで待機しているにもかかわらず。
    なぜでしょうか?
    StartTask ID: スレッド:1
    子Task ID:1 スレッド:3
    孫子Task ID:3 スレッド:4
    孫TaskCount:0
    子TaskCount:0
      (省略)
    孫TaskCount:4
    子TaskCount:4
    FinishTask ID: スレッド:1
    孫TaskCount:5
    孫TaskCount:6
    一方、ボタン2を押すと見かけ上は、なんとなく動いているようにも見えるような結果が得られましたが、根本的な問題解決になっていないことは理解しています。また、Task.Runでtokenを渡していませんが、現時点では、意図的なものです。
    StartTask ID: スレッド:1
    子Task ID:1 スレッド:3
    孫子Task ID:3 スレッド:4
    子TaskCount:0
    孫TaskCount:0
    孫TaskCount:1
    子TaskCount:1
    子TaskCount:2
    子Taskは、停止しました。
    孫TaskCount:2
    孫Taskは、停止しました。
    FinishTask ID: スレッド:1
    子タスクが、孫タスクを待つようにするには、どのようにすれば良いのでしょうか?
    詳しい方いらっしゃいましたら、御指南頂けないでしょうか?宜しくお願い致します。
    

マルチポストを報告
違反を報告
引用返信 削除キー/
■34991 / inTopicNo.2)  Re[1]: Taskの入れ子の待ち方
□投稿者/ Hongliang 大御所(616回)-(2022/01/06(Thu) 11:29:38)
  • アイコン
    Visual Studio 2019をご使用とのことですが、そうであるなら、
    Await Task.Run(
        Async Sub()
    のAsync Sub()のところに警告を示す波線が引かれていると思います。
    そこにマウスオーバーすれば警告内容がツールチップで表示されます。
    また[エラー一覧]ウィンドウにも同じ内容の警告が出ていると思います。

違反を報告
引用返信 削除キー/
■34992 / inTopicNo.3)  Re[2]: Taskの入れ子の待ち方
□投稿者/ Wan 付き人(52回)-(2022/01/06(Thu) 14:59:49)
  • アイコンHongliangさんいつもお世話になっております。
    ご指摘通り、Async Function() As Taskに変更しただけで、問題なく動きました。

    でも、どこで、Task(多分?孫Task?)がReturnされるのでしょうか?
    なぜ?Functionなのでしょうか?
    お手を煩わせてすみません。

違反を報告
引用返信 削除キー/
■34993 / inTopicNo.4)  Re[3]: Taskの入れ子の待ち方
□投稿者/ Hongliang 大御所(617回)-(2022/01/06(Thu) 15:48:17)
  • アイコン
    > でも、どこで、Task(多分?孫Task?)がReturnされるのでしょうか?
    
    Awaitを含むFunctionは、コンパイラが暗黙にTaskを返却するようなコードにコンパイルします。
    Async Function Hoge() As Task
        Debug.WriteLine("enter") ' 一度Awaitするまでは同期的に実行される
        Await Task.Delay(1000) ' Task.Delayおよびそれ以降の処理がTaskとして返値になる
        Debug.WriteLine("exit")
    End Function
    
    > なぜ?Functionなのでしょうか?
    
    Subは返値なし、Functionは返値ありです。
    Sub Hoge() As Taskとは書けません。
    Taskを返したいならFunctionでなければなりません。
    Async Subと書くケースはほぼイベントハンドラのみになるはずで、
    ほとんどの場合Async Functionになります。

違反を報告
引用返信 削除キー/
■34994 / inTopicNo.5)  Re[4]: Taskの入れ子の待ち方
□投稿者/ Wan 付き人(53回)-(2022/01/06(Thu) 16:18:42)
  • アイコンHongliangさん
    お返事有難うございます。

    Awaitは、メソッド内の実行位置に関わらず、そのメソッドが終了する時に、コンパイラが忖度して呼び出し元にTaskを返すということでしょうか?

    だから、Functionで受け取らないとダメってことですね?

    有難う御座いました。
    また、よろしくお願いします。

違反を報告
引用返信 削除キー/
■34995 / inTopicNo.6)  Re[5]: Taskの入れ子の待ち方
□投稿者/ Wan 付き人(54回)-(2022/01/06(Thu) 16:19:15)
  • アイコン解決済みです。
解決み!
違反を報告
引用返信 削除キー/



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

このトピックに書きこむ

Mode/  Pass/


- Child Tree -