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

ツリー一括表示

Nomalアイコン Taskの入れ子の待ち方2 /Wan (22/01/06(Thu) 17:05) #34997
Nomalアイコン Re[1]: Taskの入れ子の待ち方2 /Hongliang (22/01/06(Thu) 17:59) #34999
Nomalアイコン Re[1]: Taskの入れ子の待ち方2 /Wan (22/01/06(Thu) 17:57) #34998
  └Nomalアイコン Re[2]: Taskの入れ子の待ち方2 /Hongliang (22/01/06(Thu) 18:01) #35000
    └Nomalアイコン Re[3]: Taskの入れ子の待ち方2 /Wan (22/01/06(Thu) 18:30) #35001 解決み!


親記事 / ▼[ 34999 ] ▼[ 34998 ]
■34997 / 親階層)  Taskの入れ子の待ち方2
□投稿者/ Wan 付き人(56回)-(2022/01/06(Thu) 17:05:10)
  • アイコン環境/言語:[VisualBasic2019 Windows10 Basic Framework4.7.2] 
    分類:[.NET] 

    「Taskの入れ子の待ち方」の続きです。
    子Taskをラムダ式からメソッドへのデリゲートに変え、Task.Runにキャンセルトークンを渡すように変更したコードが次の通りです。
    Dim tokenSource As New CancellationTokenSource
    Private Async Sub Button6_Click(sender As Object, e As EventArgs)
    tokenSource = New CancellationTokenSource
        Debug.Print($"StartTask ID:{CurrentId} スレッド:{CurrentThread.ManagedThreadId}")
        Try
          Await Task.Run(AddressOf Test, tokenSource.Token)
        Finally
          tokenSource.Dispose()
        End Try
        Debug.Print($"FinishTask ID:{CurrentId} スレッド:{CurrentThread.ManagedThreadId}")
    End Sub
    
    Async Function Test() As Task
    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 Function
    すると、当然、Testメソッドにtokenの引数が無いので、Testメソッド側でtokenが認識できません。当然のように思えます。
    ネットでググっても、Testメソッドの引数にキャンセルトークンを渡しているものばかりが見つかります。
    ってことは、Task.Runで、キャンセルトークンを渡す必要性がそもそも無いということになるように思いますが、間違っていますでしょうか?何のためにキャンセルトークンをTask.Runで渡すのでしょうか?
    「Taskの入れ子の待ち方」では、ラムダ式で渡していたので、Task.Runでtokenを渡さなくてもメインスレッドのtokenの状態を確認することができました。
    Task.Runで、キャンセルトークンを渡しているので、孫タスク側で何か?うまい方法でtokenを認識する方法は?無いものでしょうか?
    質問の意図が通じますでしょうか?
    宜しくお願い致します。
    

違反を報告
[ □ Tree ] 返信 削除キー/

▲[ 34997 ] / 返信無し
■34999 / 1階層)  Re[1]: Taskの入れ子の待ち方2
□投稿者/ Hongliang 大御所(618回)-(2022/01/06(Thu) 17:59:07)
  • アイコン// Taskを返すメソッドは基本的にAsyncサフィクスをつけてTestAsyncのようにすると見通しがいいです。

    提示されたソースによればTest自体tokenを使っているので、そもそもそのコードではコンパイルエラーになりますよね。
    孫TaskにCancellationTokenを渡したいのであれば、Testがそれを提供する必要があるでしょう(まあCancellationTokenSourceから直接取るというケースもありますが)。
    なので、TestもCancellationTokenを引数に取る必要があるでしょう。

    引数を取るメソッド、例えばFunction Test(CancellationToken)に対してTask.Runするのであれば、ラムダ式を1つ挟むようにすればいいです。
    Task.Run(Function() Test(token), ...)
違反を報告
[ 親 34997 / □ Tree ] 返信 削除キー/

▲[ 34997 ] / ▼[ 35000 ]
■34998 / 1階層)  Re[1]: Taskの入れ子の待ち方2
□投稿者/ Wan 付き人(57回)-(2022/01/06(Thu) 17:57:32)
  • アイコン
    因みに、Task.Runにキャンセルトークンを渡さないで、ラムダ式で引数としてtokenを渡す場合は、次のようにすると上手くいきました。
    Private Async Sub Button7_Click(sender As Object, e As EventArgs) Handles Button7.Click
            tokenSource = New CancellationTokenSource
            Debug.Print($"StartTask ID:{CurrentId} スレッド:{CurrentThread.ManagedThreadId}")
            Try
                Await Task.Run(Function()
                                   Return Test2(tokenSource.Token)
                               End Function)
            Finally
                tokenSource.Dispose()
            End Try
            Debug.Print($"FinishTask ID:{CurrentId} スレッド:{CurrentThread.ManagedThreadId}")
        End Sub
    
        Async Function Test2(ByVal token As CancellationToken) As Task
            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 Function

違反を報告
[ 親 34997 / □ Tree ] 返信 削除キー/

▲[ 34998 ] / ▼[ 35001 ]
■35000 / 2階層)  Re[2]: Taskの入れ子の待ち方2
□投稿者/ Hongliang 大御所(619回)-(2022/01/06(Thu) 18:01:10)
  • アイコンつまり質問内容としては、Task.Run(..., token)のこのCancellationTokenの必要性ということですか。
    このCancellationTokenについては以下のページなどを参考にしてください。
    https://ricka.co.jp/?p=16922
違反を報告
[ 親 34997 / □ Tree ] 返信 削除キー/

▲[ 35000 ] / 返信無し
■35001 / 3階層)  Re[3]: Taskの入れ子の待ち方2
□投稿者/ Wan 付き人(58回)-(2022/01/06(Thu) 18:30:00)
  • アイコンHongliangさん
    初歩的な質問に対して、丁寧な御指南有難うございます。
    教えて頂いた、HPを含め、教えていたた内容について、熟慮したいと思います。
    また、疑問が出た場合は、お手数ですが、御指南の程よろしくお願い致します。
    有難う御座いました。
解決み!
違反を報告
[ 親 34997 / □ Tree ] 返信 削除キー/


Mode/  Pass/


- Child Tree -